Class Files Representing Various LDAP Requests
authorSunil Kumar <sunilk@mono-cvs.ximian.com>
Mon, 24 Nov 2003 03:52:45 +0000 (03:52 -0000)
committerSunil Kumar <sunilk@mono-cvs.ximian.com>
Mon, 24 Nov 2003 03:52:45 +0000 (03:52 -0000)
svn path=/trunk/mcs/; revision=20362

46 files changed:
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/AssemblyInfo.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Connection.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/InterThreadException.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAbandonRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAddRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAttribute.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAttributeSet.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAuthHandler.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAuthProvider.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapBindHandler.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapBindRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapCompareAttrNames.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapCompareRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConnection.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConstraints.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapControl.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapDN.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapDeleteRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapEntry.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapException.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedOperation.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedResponse.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapLocalException.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapMessage.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapMessageQueue.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModification.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModifyDNRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModifyRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapReferralException.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapReferralHandler.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapResponse.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapResponseQueue.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchConstraints.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchQueue.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResult.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResultReference.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResults.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUnbindRequest.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUnsolicitedNotificationListener.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUrl.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Message.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/MessageAgent.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/MessageVector.cs [new file with mode: 0755]
mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/SupportClass.cs [new file with mode: 0755]

diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/AssemblyInfo.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/AssemblyInfo.cs
new file mode 100755 (executable)
index 0000000..032715c
--- /dev/null
@@ -0,0 +1,93 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.AssemblyInfo.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Resources;
+using System.Security;
+using System.Runtime.InteropServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("C# LDAP")]
+[assembly: AssemblyDescription("Novell.Directory.Ldap")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Novell, Inc")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright(" (C) 2003 Novell, Inc")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]                
+[assembly: CLSCompliant(true)]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+//[assembly: AssemblyKeyName("")]
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Connection.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Connection.cs
new file mode 100755 (executable)
index 0000000..97e5f41
--- /dev/null
@@ -0,0 +1,1387 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.Connection.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using System.Threading;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> The class that creates a connection to the Ldap server. After the
+       /// connection is made, a thread is created that reads data from the
+       /// connection.
+       /// <p>
+       /// The application's thread sends a request to the MessageAgent class, which
+       /// creates a Message class.  The Message class calls the writeMessage method
+       /// of this class to send the request to the server. The application thread
+       /// will then query the MessageAgent class for a response.
+       /// <p>
+       /// The reader thread multiplexes response messages received from the
+       /// server to the appropriate Message class. Each Message class
+       /// has its own message queue.
+       /// <p>
+       /// Unsolicited messages are process separately, and if the application
+       /// has registered a handler, a separate thread is created for that
+       /// application's handler to process the message.
+       /// <p>
+       /// Note: the reader thread must not be a "selfish" thread, since some
+       /// operating systems do not time slice.
+       /// 
+       /// </summary>
+       /*package*/
+       sealed class Connection
+       {
+               private void  InitBlock()
+               {
+                       writeSemaphore = new System.Object();
+                       encoder = new LBEREncoder();
+                       decoder = new LBERDecoder();
+                       stopReaderMessageID = CONTINUE_READING;
+                       messages = new MessageVector(5, 5);
+                       unsolicitedListeners = new System.Collections.ArrayList(3);
+               }
+               /// <summary>  Indicates whether clones exist for LdapConnection
+               /// 
+               /// </summary>
+               /// <returns> true if clones exist, false otherwise.
+               /// </returns>
+               internal bool Cloned
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return (cloneCount > 0);
+                       }
+                       
+               }
+               /// <summary> gets the host used for this connection</summary>
+               internal System.String Host
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return host;
+                       }
+                       
+               }
+               /// <summary> gets the port used for this connection</summary>
+               internal int Port
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return port;
+                       }
+                       
+               }
+               /// <summary> gets the writeSemaphore id used for active bind operation</summary>
+               /// <summary> sets the writeSemaphore id used for active bind operation</summary>
+               internal int BindSemId
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return bindSemaphoreId;
+                       }
+                       
+                       /* package */
+                       
+                       set
+                       {
+                               bindSemaphoreId = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> checks if the writeSemaphore id used for active bind operation is clear</summary>
+               internal bool BindSemIdClear
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               if (bindSemaphoreId == 0)
+                               {
+                                       return true;
+                               }
+                               return false;
+                       }
+                       
+               }
+               /// <summary> Return whether the application is bound to this connection.
+               /// Note: an anonymous bind returns false - not bound
+               /// </summary>
+               internal bool Bound
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               if (bindProperties != null)
+                               {
+                                       // Bound if not anonymous
+                                       return (!bindProperties.Anonymous);
+                               }
+                               return false;
+                       }
+                       
+               }
+               /// <summary> Return whether a connection has been made</summary>
+               internal bool Connected
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return (in_Renamed != null);
+                       }
+                       
+               }
+               /// <summary> 
+               /// Sets the authentication credentials in the object
+               /// and set flag indicating successful bind.
+               /// 
+               /// 
+               /// <br><br>
+               /// </summary>
+               /// <returns>  The BindProperties object for this connection.
+               /// </returns>
+               /// <summary> 
+               /// Sets the authentication credentials in the object
+               /// and set flag indicating successful bind.
+               /// 
+               /// 
+               /// <br><br>
+               /// </summary>
+               /// <param name="bindProps">  The BindProperties object to set.
+               /// </param>
+               internal BindProperties BindProperties
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return bindProperties;
+                       }
+                       
+                       /* package */
+                       
+                       set
+                       {
+                               bindProperties = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Gets the current referral active on this connection if created to
+               /// follow referrals.
+               /// 
+               /// </summary>
+               /// <returns> the active referral url
+               /// </returns>
+               /// <summary> Sets the current referral active on this connection if created to
+               /// follow referrals.
+               /// </summary>
+               internal ReferralInfo ActiveReferral
+               {
+
+                       
+                       get
+                       {
+                               return activeReferral;
+                       }
+                       
+
+                       
+                       set
+                       {
+                               activeReferral = value;
+                               return ;
+                       }
+                       
+               }
+               
+               /// <summary> Returns the name of this Connection, used for debug only
+               /// 
+               /// </summary>
+               /// <returns> the name of this connection
+               /// </returns>
+               internal System.String ConnectionName
+               {
+                       /*package*/
+                       
+                       get
+                       {
+                               return name;
+                       }
+                       
+               }
+               
+               private System.Object writeSemaphore;
+               private int writeSemaphoreOwner = 0;
+               private int writeSemaphoreCount = 0;
+               
+               // We need a message number for disconnect to grab the semaphore,
+               // but may not have one, so we invent a unique one.
+               private int ephemeralId = - 1;
+               private BindProperties bindProperties = null;
+               private int bindSemaphoreId = 0; // 0 is never used by to lock a semaphore
+               
+               private SupportClass.ThreadClass reader = null; // New thread that reads data from the server.
+               private SupportClass.ThreadClass deadReader = null; // Identity of last reader thread
+               private System.IO.IOException deadReaderException = null; // Last exception of reader
+               
+               private LBEREncoder encoder;
+               private LBERDecoder decoder;
+               
+               /*
+               * socket is the current socket being used.
+               * nonTLSBackup is the backup socket if startTLS is called.
+               * if nonTLSBackup is null then startTLS has not been called,
+               * or stopTLS has been called to end TLS protection
+               */
+               private System.Net.Sockets.TcpClient socket = null;
+               private System.Net.Sockets.TcpClient nonTLSBackup = null;
+               
+               private System.IO.Stream in_Renamed = null;
+               private System.IO.Stream out_Renamed = null;
+               // When set to true the client connection is up and running
+               private bool clientActive = true;
+               
+               // Indicates we have received a server shutdown unsolicited notification
+               private bool unsolSvrShutDnNotification = false;
+               
+               //  Ldap message IDs are all positive numbers so we can use negative
+               //  numbers as flags.  This are flags assigned to stopReaderMessageID
+               //  to tell the reader what state we are in.
+               private const int CONTINUE_READING = - 99;
+               private const int STOP_READING = - 98;
+               
+               //  Stops the reader thread when a Message with the passed-in ID is read.
+               //  This parameter is set by stopReaderOnReply and stopTLS
+               private int stopReaderMessageID;
+               
+               
+               // Place to save message information classes
+               private MessageVector messages;
+               
+               // Connection created to follow referral
+               private ReferralInfo activeReferral = null;
+               
+               // Place to save unsolicited message listeners
+               private System.Collections.ArrayList unsolicitedListeners;
+               
+               // The LdapSocketFactory to be used as the default to create new connections
+//             private static LdapSocketFactory socketFactory = null;
+               // The LdapSocketFactory used for this connection
+//             private LdapSocketFactory mySocketFactory;
+               private System.String host = null;
+               private int port = 0;
+               // Number of clones in addition to original LdapConnection using this
+               // connection.
+               private int cloneCount = 0;
+               // Connection number & name used only for debug
+               private System.String name = "";
+               private static System.Object nameLock; // protect connNum
+               private static int connNum = 0;
+               
+               // These attributes can be retreived using the getProperty
+               // method in LdapConnection.  Future releases might require
+               // these to be local variables that can be modified using
+               // the setProperty method.
+               /* package */
+               internal static System.String sdk;
+               /* package */
+               internal static System.Int32 protocol;
+               /* package */
+               internal static System.String security = "simple";
+               
+               /// <summary> Create a new Connection object
+               /// 
+               /// </summary>
+               /// <param name="factory">specifies the factory to use to produce SSL sockets.
+               /// </param>
+               /* package */
+//             internal Connection(LdapSocketFactory factory)
+               internal Connection()
+               {
+                       InitBlock();
+                       return ;
+               }
+               
+               /// <summary> Copy this Connection object.
+               /// 
+               /// <p>This is not a true clone, but creates a new object encapsulating
+               /// part of the connection information from the original object.
+               /// The new object will have the same default socket factory,
+               /// designated socket factory, host, port, and protocol version
+               /// as the original object.
+               /// The new object is NOT be connected to the host.</p>
+               /// 
+               /// </summary>
+               /// <returns> a shallow copy of this object
+               /// </returns>
+               /* package */
+               internal System.Object copy()
+               {
+                       Connection c = new Connection();
+                       c.host = this.host;
+                       c.port = this.port;
+                       Novell.Directory.Ldap.Connection.protocol = Connection.protocol;
+                       return c;
+               }
+               
+               /// <summary> Acquire a simple counting semaphore that synchronizes state affecting
+               /// bind. This method generates an ephemeral message id (negative number).
+               /// 
+               /// We bind using the message ID because a different thread may unlock
+               /// the semaphore than the one that set it.  It is cleared when the
+               /// response to the bind is processed, or when the bind operation times out.
+               /// 
+               /// Returns when the semaphore is acquired
+               /// 
+               /// </summary>
+               /// <returns> the ephemeral message id that identifies semaphore's owner
+               /// </returns>
+               /* package */
+               internal int acquireWriteSemaphore()
+               {
+                       return acquireWriteSemaphore(0);
+               }
+               
+               /// <summary> Acquire a simple counting semaphore that synchronizes state affecting
+               /// bind. The semaphore is held by setting a value in writeSemaphoreOwner.
+               /// 
+               /// We bind using the message ID because a different thread may unlock
+               /// the semaphore than the one that set it.  It is cleared when the
+               /// response to the bind is processed, or when the bind operation times out.
+               /// Returns when the semaphore is acquired.
+               /// 
+               /// </summary>
+               /// <param name="msgId">a value that identifies the owner of this semaphore. A
+               /// value of zero means assign a unique semaphore value.
+               /// 
+               /// </param>
+               /// <returns> the semaphore value used to acquire the lock
+               /// </returns>
+               /* package */
+               internal int acquireWriteSemaphore(int msgId)
+               {
+                       int id = msgId;
+                       lock (writeSemaphore)
+                       {
+                               if (id == 0)
+                               {
+                                       ephemeralId = ((ephemeralId == System.Int32.MinValue)?(ephemeralId = - 1):--ephemeralId);
+                                       id = ephemeralId;
+                               }
+                               while (true)
+                               {
+                                       if (writeSemaphoreOwner == 0)
+                                       {
+                                               // we have acquired the semahpore
+                                               writeSemaphoreOwner = id;
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               if (writeSemaphoreOwner == id)
+                                               {
+                                                       // we already own the semahpore
+                                                       break;
+                                               }
+                                               try
+                                               {
+                                                       // Keep trying for the lock
+                                                       System.Threading.Monitor.Wait(writeSemaphore);
+                                                       continue;
+                                               }
+                                               catch (System.Threading.ThreadInterruptedException ex)
+                                               {
+                                                       // Keep trying for the lock
+                                                       continue;
+                                               }
+                                       }
+                               }
+                               writeSemaphoreCount++;
+                       }
+                       return id;
+               }
+               
+               /// <summary> Release a simple counting semaphore that synchronizes state affecting
+               /// bind.  Frees the semaphore when number of acquires and frees for this
+               /// thread match.
+               /// 
+               /// </summary>
+               /// <param name="msgId">a value that identifies the owner of this semaphore
+               /// </param>
+               /* package */
+               internal void  freeWriteSemaphore(int msgId)
+               {
+                       lock (writeSemaphore)
+                       {
+                               if (writeSemaphoreOwner == 0)
+                               {
+                                       throw new System.SystemException("Connection.freeWriteSemaphore(" + msgId + "): semaphore not owned by any thread");
+                               }
+                               else if (writeSemaphoreOwner != msgId)
+                               {
+                                       throw new System.SystemException("Connection.freeWriteSemaphore(" + msgId + "): thread does not own the semaphore, owned by " + writeSemaphoreOwner);
+                               }
+                               // if all instances of this semaphore for this thread are released,
+                               // wake up all threads waiting.
+                               if (--writeSemaphoreCount == 0)
+                               {
+                                       writeSemaphoreOwner = 0;
+                                       System.Threading.Monitor.Pulse(writeSemaphore);
+                               }
+                       }
+                       return ;
+               }
+               
+               /*
+               * Wait until the reader thread ID matches the specified parameter.
+               * Null = wait for the reader to terminate
+               * Non Null = wait for the reader to start
+               * Returns when the ID matches, i.e. reader stopped, or reader started.
+               *
+               * @param the thread id to match
+               */
+               private void  waitForReader(SupportClass.ThreadClass thread)
+               {
+                       // wait for previous reader thread to terminate
+                       System.Threading.Thread rInst;
+                       System.Threading.Thread tInst;
+                       if(reader!=null)
+                       {
+                               rInst=reader.Instance;
+                       }
+                       else
+                       {
+                               rInst=null;
+                       }
+
+                       if(thread!=null)
+                       {
+                               tInst=thread.Instance;
+                       }
+                       else
+                       {
+                               tInst=null;
+                       }
+//                     while (reader != thread)
+                       while (!Object.Equals(rInst,tInst))
+                       {
+                               // Don't initialize connection while previous reader thread still
+                               // active.
+                               try
+                               {
+                                       /*
+                                       * The reader thread may start and immediately terminate.
+                                       * To prevent the waitForReader from waiting forever
+                                       * for the dead to rise, we leave traces of the deceased.
+                                       * If the thread is already gone, we throw an exception.
+                                       */
+                                       if (thread == deadReader)
+                                       {
+                                               if (thread == null)
+                                               /* then we wanted a shutdown */
+                                                       return ;
+                                               System.IO.IOException lex = deadReaderException;
+                                               deadReaderException = null;
+                                               deadReader = null;
+                                               // Reader thread terminated
+                                               throw new LdapException(ExceptionMessages.CONNECTION_READER, LdapException.CONNECT_ERROR, null, lex);
+                                       }
+                                       lock (this)
+                                       {
+                                               System.Threading.Monitor.Wait(this, TimeSpan.FromMilliseconds(5));
+                                       }
+                               }
+                               catch (System.Threading.ThreadInterruptedException ex)
+                               {
+                                       ;
+                               }
+                               if(reader!=null)
+                               {
+                                       rInst=reader.Instance;
+                               }
+                               else
+                               {
+                                       rInst=null;
+                               }
+
+                               if(thread!=null)
+                               {
+                                       tInst=thread.Instance;
+                               }
+                               else
+                               {
+                                       tInst=null;
+                               }
+
+                       }
+                       deadReaderException = null;
+                       deadReader = null;
+                       return ;
+               }
+               
+               /// <summary> Constructs a TCP/IP connection to a server specified in host and port.
+               /// 
+               /// </summary>
+               /// <param name="host">The host to connect to.
+               /// <br><br>
+               /// </param>
+               /// <param name="port">The port on the host to connect to.
+               /// </param>
+               /* package */
+               internal void  connect(System.String host, int port)
+               {
+                       connect(host, port, 0);
+                       return ;
+               }
+               
+               /// <summary> Constructs a TCP/IP connection to a server specified in host and port.
+               /// Starts the reader thread.
+               /// 
+               /// </summary>
+               /// <param name="host">The host to connect to.
+               /// <br><br>
+               /// </param>
+               /// <param name="port">The port on the host to connect to.
+               /// <br><br>
+               /// </param>
+               /// <param name="semaphoreId">The write semaphore ID to use for the connect
+               /// </param>
+               private void  connect(System.String host, int port, int semaphoreId)
+               {
+                       /* Synchronized so all variables are in a consistant state and
+                       * so that another thread isn't doing a connect, disconnect, or clone
+                       * at the same time.
+                       */
+                       // Wait for active reader to terminate
+                       waitForReader(null);
+                       
+                       // Clear the server shutdown notification flag.  This should already
+                       // be false unless of course we are reusing the same Connection object
+                       // after a server shutdown notification
+                       unsolSvrShutDnNotification = false;
+                       
+                       int semId = acquireWriteSemaphore(semaphoreId);
+                       
+                       // Make socket connection to specified host and port
+                       if (port == 0)
+                       {
+                               port = 389;//LdapConnection.DEFAULT_PORT;
+                       }
+                       
+                       try
+                       {
+                               if ((in_Renamed == null) || (out_Renamed == null))
+                               {
+                                   socket = new System.Net.Sockets.TcpClient(host, port);
+                                       
+                                       in_Renamed = (System.IO.Stream) socket.GetStream();
+                                       out_Renamed = (System.IO.Stream) socket.GetStream();
+                               }
+                               else
+                               {
+                                       Console.WriteLine( "connect input/out Stream specified");
+
+                               }
+                       }
+                       catch (System.IO.IOException ioe)
+                       {
+                               // Unable to connect to server host:port
+//                             freeWriteSemaphore(semId);
+                               throw new LdapException(ExceptionMessages.CONNECTION_ERROR, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, null, ioe);
+                       }
+                       // Set host and port
+                       this.host = host;
+                       this.port = port;
+                       // start the reader thread
+                       this.startReader();
+                       freeWriteSemaphore(semId);
+                       clientActive = true; // Client is up
+                       return ;
+               }
+               
+               /// <summary>  Increments the count of cloned connections</summary>
+               /* package */
+               internal void  incrCloneCount()
+               {
+                       lock (this)
+                       {
+                               cloneCount++;
+                               return ;
+                       }
+               }
+               
+               /// <summary> Destroys a clone of <code>LdapConnection</code>.
+               /// 
+               /// <p>This method first determines if only one <code>LdapConnection</code>
+               /// object is associated with this connection, i.e. if no clone exists.</p>
+               /// 
+               /// <p>If no clone exists, the socket is closed, and the current
+               /// <code>Connection</code> object is returned.</p>
+               /// 
+               /// <p>If multiple <code>LdapConnection</code> objects are associated
+               /// with this connection, i.e. clones exist, a {@link #copy} of the
+               /// this object is made, but is not connected to any host. This
+               /// disassociates that clone from the original connection.  The new
+               /// <code>Connection</code> object is returned.
+               /// 
+               /// <p>Only one destroyClone instance is allowed to run at any one time.</p>
+               /// 
+               /// <p>If the connection is closed, any threads waiting for operations
+               /// on that connection will wake with an LdapException indicating
+               /// the connection is closed.</p>
+               /// 
+               /// </summary>
+               /// <param name="apiCall"><code>true</code> indicates the application is closing the
+               /// connection or or creating a new one by calling either the
+               /// <code>connect</code> or <code>disconnect</code> methods
+               /// of <code>LdapConnection</code>.  <code>false</code>
+               /// indicates that <code>LdapConnection</code> is being finalized.
+               /// 
+               /// </param>
+               /// <returns> a Connection object or null if finalizing.
+               /// </returns>
+               /* package */
+               internal Connection destroyClone(bool apiCall)
+               {
+                       lock (this)
+                       {
+                               Connection conn = this;
+                               
+                               if (cloneCount > 0)
+                               {
+                                       cloneCount--;
+                                       // This is a clone, set a new connection object.
+                                       if (apiCall)
+                                       {
+                                               conn = (Connection) this.copy();
+                                       }
+                                       else
+                                       {
+                                               conn = null;
+                                       }
+                               }
+                               else
+                               {
+                                       if (in_Renamed != null)
+                                       {
+                                               // Not a clone and connected
+                                               /*
+                                               * Either the application has called disconnect or connect
+                                               * resulting in the current connection being closed. If the
+                                               * application has any queues waiting on messages, we
+                                               * need wake these up so the application does not hang.
+                                               * The boolean flag indicates whether the close came
+                                               * from an API call or from the object being finalized.
+                                               */
+                                               InterThreadException notify = new InterThreadException((apiCall?ExceptionMessages.CONNECTION_CLOSED:ExceptionMessages.CONNECTION_FINALIZED), null, LdapException.CONNECT_ERROR, null, null);
+                                               // Destroy old connection
+                                               shutdown("destroy clone", 0, notify);
+                                       }
+                               }
+                               return conn;
+                       }
+               }
+               
+               /// <summary> sets the default socket factory
+               /// 
+               /// </summary>
+               /// <param name="factory">the default factory to set
+               /// </param>
+               /* package */
+               /// <summary> gets the socket factory used for this connection
+               /// 
+               /// </summary>
+               /// <returns> the default factory for this connection
+               /// </returns>
+               /* package */
+               
+               /// <summary> clears the writeSemaphore id used for active bind operation</summary>
+               /* package */
+               internal void  clearBindSemId()
+               {
+                       bindSemaphoreId = 0;
+                       return ;
+               }
+               
+               /// <summary> Writes an LdapMessage to the Ldap server over a socket.
+               /// 
+               /// </summary>
+               /// <param name="info">the Message containing the message to write.
+               /// </param>
+               /* package */
+               internal void  writeMessage(Message info)
+               {
+                       messages.Add(info);
+                       // For bind requests, if not connected, attempt to reconnect
+                       if (info.BindRequest && (Connected == false) && ((System.Object) host != null))
+                       {
+                               connect(host, port, info.MessageID);
+                       }
+                       LdapMessage msg = info.Request;
+                       writeMessage(msg);
+                       return ;
+               }
+               
+               
+               /// <summary> Writes an LdapMessage to the Ldap server over a socket.
+               /// 
+               /// </summary>
+               /// <param name="msg">the message to write.
+               /// </param>
+               /* package */
+               internal void  writeMessage(LdapMessage msg)
+               {
+                       int id;
+                       // Get the correct semaphore id for bind operations
+                       if (bindSemaphoreId == 0)
+                       {
+                               // Semaphore id for normal operations
+                               id = msg.MessageID;
+                       }
+                       else
+                       {
+                               // Semaphore id for sasl bind operations
+                               id = bindSemaphoreId;
+                       }
+                       System.IO.Stream myOut = out_Renamed;
+                       
+                       acquireWriteSemaphore(id);
+                       try
+                       {
+                               if (myOut == null)
+                               {
+                                       throw new System.IO.IOException("Output stream not initialized");
+                               }
+                               sbyte[] ber = msg.Asn1Object.getEncoding(encoder);
+                               myOut.Write(SupportClass.ToByteArray(ber), 0, ber.Length);
+                               myOut.Flush();
+                       }
+                       catch (System.IO.IOException ioe)
+                       {
+                               
+                               /*
+                               * IOException could be due to a server shutdown notification which
+                               * caused our Connection to quit.  If so we send back a slightly
+                               * different error message.  We could have checked this a little
+                               * earlier in the method but that would be an expensive check each
+                               * time we send out a message.  Since this shutdown request is
+                               * going to be an infrequent occurence we check for it only when
+                               * we get an IOException.  shutdown() will do the cleanup.
+                               */
+                               if (clientActive)
+                               {
+                                       // We beliefe the connection was alive
+                                       if (unsolSvrShutDnNotification)
+                                       {
+                                               // got server shutdown
+                                               throw new LdapException(ExceptionMessages.SERVER_SHUTDOWN_REQ, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, null, ioe);
+                                       }
+                                       
+                                       // Other I/O Exceptions on host:port are reported as is
+                                       throw new LdapException(ExceptionMessages.IO_EXCEPTION, new System.Object[]{host, port}, LdapException.CONNECT_ERROR, null, ioe);
+                               }
+                       }
+                       finally
+                       {
+                               freeWriteSemaphore(id);
+                       }
+                       return ;
+               }
+               
+               /// <summary> Returns the message agent for this msg ID</summary>
+               /* package */
+               internal MessageAgent getMessageAgent(int msgId)
+               {
+                       Message info = messages.findMessageById(msgId);
+                       return info.MessageAgent;
+               }
+               
+               /// <summary> Removes a Message class from the Connection's list
+               /// 
+               /// </summary>
+               /// <param name="info">the Message class to remove from the list
+               /// </param>
+               /* package */
+               internal void  removeMessage(Message info)
+               {
+                       bool done = SupportClass.VectorRemoveElement(messages, info);
+                       return ;
+               }
+               
+               /// <summary> Cleans up resources associated with this connection.</summary>
+               ~Connection()
+               {
+                       shutdown("Finalize", 0, null);
+                       return ;
+               }
+               /// <summary> Cleans up resources associated with this connection.
+               /// This method may be called by finalize() for the connection, or it may
+               /// be called by LdapConnection.disconnect().
+               /// Should not have a writeSemaphore lock in place, as deadlock can occur
+               /// while abandoning connections.
+               /// </summary>
+               private void  shutdown(System.String reason, int semaphoreId, InterThreadException notifyUser)
+               {
+                       Message info = null;
+                       if (!clientActive)
+                       {
+                               return ;
+                       }
+                       clientActive = false;
+                       while (true)
+                       {
+                               // remove messages from connection list and send abandon
+                               try
+                               {
+                                       System.Object temp_object;
+                                       temp_object = messages[0];
+                                       messages.RemoveAt(0);
+                                       info = (Message) temp_object;
+                               }
+                               catch (ArgumentOutOfRangeException ex)
+                               {
+                                       // No more messages
+                                       break;
+                               }
+                               info.Abandon(null, notifyUser); // also notifies the application
+                       }
+                       
+                       int semId = acquireWriteSemaphore(semaphoreId);
+                       // Now send unbind if socket not closed
+                       if ((bindProperties != null) && (out_Renamed != null) && (!bindProperties.Anonymous))
+                       {
+                               try
+                               {
+                                       LdapMessage msg = new LdapUnbindRequest(null);
+                                       sbyte[] ber = msg.Asn1Object.getEncoding(encoder);
+                                       out_Renamed.Write(SupportClass.ToByteArray(ber), 0, ber.Length);
+                                       out_Renamed.Flush();
+                               }
+                               catch (System.Exception ex)
+                               {
+                                       ; // don't worry about error
+                               }
+                       }
+                       bindProperties = null;
+                       
+                       in_Renamed = null;
+                       out_Renamed = null;
+                       if (socket != null)
+                       {
+                               // Close the socket
+                               try
+                               {
+                                       socket.Close();
+                               }
+                               catch (System.IO.IOException ie)
+                               {
+                                       // ignore problem closing socket
+                               }
+                               socket = null;
+                       }
+                       freeWriteSemaphore(semId);
+                       return ;
+               }
+               
+               /// <summary> This tests to see if there are any outstanding messages.  If no messages
+               /// are in the queue it returns true.  Each message will be tested to
+               /// verify that it is complete.
+               /// <I>The writeSemaphore must be set for this method to be reliable!</I>
+               /// 
+               /// </summary>
+               /// <returns> true if no outstanding messages
+               /// </returns>
+               /* package */
+               internal bool areMessagesComplete()
+               {
+                       System.Object[] messages = this.messages.ObjectArray;
+                       int length = messages.Length;
+                       
+                       // Check if SASL bind in progress
+                       if (bindSemaphoreId != 0)
+                       {
+                               return false;
+                       }
+                       
+                       // Check if any messages queued
+                       if (length == 0)
+                       {
+                               return true;
+                       }
+                       
+                       for (int i = 0; i < length; i++)
+                       {
+                               if (((Message) messages[i]).Complete == false)
+                                       return false;
+                       }
+                       return true;
+               }
+               
+               /// <summary> The reader thread will stop when a reply is read with an ID equal
+               /// to the messageID passed in to this method.  This is used by
+               /// LdapConnection.StartTLS.
+               /// </summary>
+               /* package */
+               internal void  stopReaderOnReply(int messageID)
+               {
+                       
+                       this.stopReaderMessageID = messageID;
+                       return ;
+               }
+               
+               /// <summary>startReader
+               /// startReader should be called when socket and io streams have been
+               /// set or changed.  In particular after client.Connection.startTLS()
+               /// It assumes the reader thread is not running.
+               /// </summary>
+               /* package */
+               internal void  startReader()
+               {
+                       // Start Reader Thread
+                       SupportClass.ThreadClass r =new SupportClass.ThreadClass(new System.Threading.ThreadStart(new ReaderThread(this).Run));
+//                     Thread r = new Thread(new ThreadStart(new ReaderThread(this).Run));
+                       r.IsBackground = true; // If the last thread running, allow exit.
+                       r.Start();
+                       waitForReader(r);
+                       return ;
+               }
+               
+               /// <summary> StartsTLS, in this package, assumes the caller has:
+               /// 1) Acquired the writeSemaphore
+               /// 2) Stopped the reader thread
+               /// 3) checked that no messages are outstanding on this connection.
+               /// 
+               /// After calling this method upper layers should start the reader
+               /// by calling startReader()
+               /// 
+               /// In the client.Connection, StartTLS assumes Ldap.LdapConnection will
+               /// stop and start the reader thread.  Connection.StopTLS will stop
+               /// and start the reader thread.
+               /// </summary>
+               /* package */
+/*             internal void  startTLS()
+               {
+                       if (this.mySocketFactory == null)
+                       {
+                               throw new LdapException(ExceptionMessages.NO_TLS_FACTORY, LdapException.TLS_NOT_SUPPORTED, null);
+                       }
+                       else if (!(this.mySocketFactory is LdapTLSSocketFactory))
+                       {
+                               throw new LdapException(ExceptionMessages.WRONG_FACTORY, LdapException.TLS_NOT_SUPPORTED, null);
+                       }
+                       
+                       try
+                       {
+                               waitForReader(null);
+                               this.nonTLSBackup = this.socket;
+                               this.socket = ((LdapTLSSocketFactory) this.mySocketFactory).createSocket(this.socket);
+                               this.in_Renamed = (System.IO.Stream) socket.GetStream();
+                               this.out_Renamed = (System.IO.Stream) socket.GetStream();
+                               
+                               if (Debug.Ldap_DEBUG)
+                               {
+                                       Debug.trace(Debug.TLS, "connection.startTLS, nonTLSBackup:" + nonTLSBackup + ", TLSSocket:" + socket + ", input:" + in_Renamed + "," + "output:" + out_Renamed);
+                               }
+                       }
+                       catch (System.Exception uhe)
+                       {
+                               this.nonTLSBackup = null;
+                               throw new LdapException("The host is unknown", LdapException.CONNECT_ERROR, null, uhe);
+                       }
+                       catch (System.IO.IOException ioe)
+                       {
+                               this.nonTLSBackup = null;
+                               throw new LdapException("Could not negotiate a secure connection", LdapException.CONNECT_ERROR, null, ioe);
+                       }
+                       return ;
+               }
+*/             
+               /*
+               * Stops TLS.
+               *
+               * StopTLS, in this package, assumes the caller has:
+               *  1) blocked writing (acquireWriteSemaphore).
+               *  2) checked that no messages are outstanding.
+               *
+               *  StopTLS Needs to do the following:
+               *  1) close the current socket
+               *      - This stops the reader thread
+               *      - set STOP_READING flag on stopReaderMessageID so that
+               *        the reader knows that the IOException is planned.
+               *  2) replace the current socket with nonTLSBackup,
+               *  3) and set nonTLSBackup to null;
+               *  4) reset input and outputstreams
+               *  5) start the reader thread by calling startReader
+               *
+               *  Note: Sun's JSSE doesn't allow the nonTLSBackup socket to be
+               * used any more, even though autoclose was false: you get an IOException.
+               * IBM's JSSE hangs when you close the JSSE socket.
+               */
+               /* package */
+/*             internal void  stopTLS()
+               {
+                       try
+                       {
+                               this.stopReaderMessageID = Connection.STOP_READING;
+                               this.socket.Close();
+                               waitForReader(null);
+                               this.socket = this.nonTLSBackup;
+                               this.in_Renamed = (System.IO.Stream) this.socket.GetStream();
+                               this.out_Renamed = (System.IO.Stream) this.socket.GetStream();
+                               if (Debug.Ldap_DEBUG)
+                               {
+                                       Debug.trace(Debug.TLS, "connection.stopTLS, nonTLSBackup:" + nonTLSBackup + ", TLSSocket:" + socket + ", input:" + in_Renamed + "," + "output:" + out_Renamed);
+                               }
+                               // Allow the new reader to start
+                               this.stopReaderMessageID = Connection.CONTINUE_READING;
+                       }
+                       catch (System.IO.IOException ioe)
+                       {
+                               throw new LdapException(ExceptionMessages.STOPTLS_ERROR, LdapException.CONNECT_ERROR, null, ioe);
+                       }
+                       finally
+                       {
+                               this.nonTLSBackup = null;
+                               startReader();
+                       }
+                       return ;
+               }
+*///TLS not supported in first release         
+
+               public class ReaderThread
+               {
+                       private void  InitBlock(Connection enclosingInstance)
+                       {
+                               this.enclosingInstance = enclosingInstance;
+                       }
+                       private Connection enclosingInstance;
+                       public Connection Enclosing_Instance
+                       {
+                               get
+                               {
+                                       return enclosingInstance;
+                               }
+                               
+                       }
+                       public ReaderThread(Connection enclosingInstance)
+                       {
+                               InitBlock(enclosingInstance);
+                               return ;
+                       }
+                       
+                       /// <summary> This thread decodes and processes RfcLdapMessage's from the server.
+                       /// 
+                       /// Note: This thread needs a graceful shutdown implementation.
+                       /// </summary>
+                       public virtual void  Run()
+                       {
+                               
+                               System.String reason = "reader: thread stopping";
+                               InterThreadException notify = null;
+                               Message info = null;
+                               System.IO.IOException ioex = null;
+                               this.enclosingInstance.reader = SupportClass.ThreadClass.Current();                             
+//                             Enclosing_Instance.reader = SupportClass.ThreadClass.Current();
+//                             Console.WriteLine("Inside run:" + this.enclosingInstance.reader.Name);
+                               try
+                               {
+                                       for (; ; )
+                                       {
+                                               // -------------------------------------------------------
+                                               // Decode an RfcLdapMessage directly from the socket.
+                                               // -------------------------------------------------------
+                                               Asn1Identifier asn1ID;
+                                               System.IO.Stream myIn;
+                                               /* get current value of in, keep value consistant
+                                               * though the loop, i.e. even during shutdown
+                                               */
+                                               myIn = this.enclosingInstance.in_Renamed;
+                                               if (myIn == null)
+                                               {
+                                                       break;
+                                               }
+                                               asn1ID = new Asn1Identifier(myIn);
+                                               int tag = asn1ID.Tag;
+                                               if (asn1ID.Tag != Asn1Sequence.TAG)
+                                               {
+                                                       continue; // loop looking for an RfcLdapMessage identifier
+                                               }
+                                               
+                                               // Turn the message into an RfcMessage class
+                                               Asn1Length asn1Len = new Asn1Length(myIn);
+                                               
+                                               RfcLdapMessage msg = new RfcLdapMessage(this.enclosingInstance.decoder, myIn, asn1Len.Length);
+                                               
+                                               // ------------------------------------------------------------
+                                               // Process the decoded RfcLdapMessage.
+                                               // ------------------------------------------------------------
+                                               int msgId = msg.MessageID;
+                                               
+                                               // Find the message which requested this response.
+                                               // It is possible to receive a response for a request which
+                                               // has been abandoned. If abandoned, throw it away
+                                               try
+                                               {
+                                                       info = this.enclosingInstance.messages.findMessageById(msgId);
+                                                       info.putReply(msg); // queue & wake up waiting thread
+                                               }
+                                               catch (System.FieldAccessException ex)
+                                               {
+                                                       
+                                                       /*
+                                                       * We get the NoSuchFieldException when we could not find
+                                                       * a matching message id.  First check to see if this is
+                                                       * an unsolicited notification (msgID == 0). If it is not
+                                                       * we throw it away. If it is we call any unsolicited
+                                                       * listeners that might have been registered to listen for these
+                                                       * messages.
+                                                       */
+                                                       
+                                                       
+                                                       /* Note the location of this code.  We could have required
+                                                       * that message ID 0 be just like other message ID's but
+                                                       * since message ID 0 has to be treated specially we have
+                                                       * a separate check for message ID 0.  Also note that
+                                                       * this test is after the regular message list has been
+                                                       * checked for.  We could have always checked the list
+                                                       * of messages after checking if this is an unsolicited
+                                                       * notification but that would have inefficient as
+                                                       * message ID 0 is a rare event (as of this time).
+                                                       */
+                                                       if (msgId == 0)
+                                                       {
+                                                               
+                                                               
+                                                               // Notify any listeners that might have been registered
+                                                               this.enclosingInstance.notifyAllUnsolicitedListeners(msg);
+                                                               
+                                                               /*
+                                                               * Was this a server shutdown unsolicited notification.
+                                                               * IF so we quit. Actually calling the return will
+                                                               * first transfer control to the finally clause which
+                                                               * will do the necessary clean up.
+                                                               */
+                                                               if (this.enclosingInstance.unsolSvrShutDnNotification)
+                                                               {
+                                                                       notify = new InterThreadException(ExceptionMessages.SERVER_SHUTDOWN_REQ, new System.Object[]{this.enclosingInstance.host, this.enclosingInstance.port}, LdapException.CONNECT_ERROR, null, null);
+                                                                       
+                                                                       return ;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               
+                                                       }
+                                               }
+                                               if ((this.enclosingInstance.stopReaderMessageID == msgId) || (this.enclosingInstance.stopReaderMessageID == Novell.Directory.Ldap.Connection.STOP_READING))
+                                               {
+                                                       // Stop the reader Thread.
+                                                       return ;
+                                               }
+                                       }
+                               }
+                               catch (System.IO.IOException ioe)
+                               {
+                                       
+                                       ioex = ioe;
+                                       if ((this.enclosingInstance.stopReaderMessageID != Novell.Directory.Ldap.Connection.STOP_READING) && this.enclosingInstance.clientActive)
+                                       {
+                                               // Connection lost waiting for results from host:port
+                                               notify = new InterThreadException(ExceptionMessages.CONNECTION_WAIT, new System.Object[]{this.enclosingInstance.host, this.enclosingInstance.port}, LdapException.CONNECT_ERROR, ioe, info);
+                                       }
+                                       // The connection is no good, don't use it any more
+                                       this.enclosingInstance.in_Renamed = null;
+                                       this.enclosingInstance.out_Renamed = null;
+                               }
+                               finally
+                               {
+                                       /*
+                                       * There can be four states that the reader can be in at this point:
+                                       *  1) We are starting TLS and will be restarting the reader
+                                       *     after we have negotiated TLS.
+                                       *      - Indicated by whether stopReaderMessageID does not
+                                       *        equal CONTINUE_READING.
+                                       *      - Don't call Shutdown.
+                                       *  2) We are stoping TLS and will be restarting after TLS is
+                                       *     stopped.
+                                       *      - Indicated by an IOException AND stopReaderMessageID equals
+                                       *        STOP_READING - in which case notify will be null.
+                                       *      - Don't call Shutdown
+                                       *  3) We receive a Server Shutdown notification.
+                                       *      - Indicated by messageID equal to 0.
+                                       *      - call Shutdown.
+                                       *  4) Another error occured
+                                       *      - Indicated by an IOException AND notify is not NULL
+                                       *      - call Shutdown.
+                                       */
+                                       if ((!this.enclosingInstance.clientActive) || (notify != null))
+                                       {
+                                               //#3 & 4
+                                               this.enclosingInstance.shutdown(reason, 0, notify);
+                                       }
+                                       else
+                                       {
+                                               this.enclosingInstance.stopReaderMessageID = Novell.Directory.Ldap.Connection.CONTINUE_READING;
+                                       }
+                               }
+                               this.enclosingInstance.deadReaderException = ioex;
+                               this.enclosingInstance.deadReader = this.enclosingInstance.reader;
+                               this.enclosingInstance.reader = null;
+                               return ;
+                       }
+               } // End class ReaderThread
+               
+               /// <summary>Add the specific object to the list of listeners that want to be
+               /// notified when an unsolicited notification is received.
+               /// </summary>
+               /* package */
+               internal void  AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
+               {
+                       unsolicitedListeners.Add(listener);
+                       return ;
+               }
+               
+               /// <summary>Remove the specific object from current list of listeners</summary>
+               /* package */
+               internal void  RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
+               {
+                       SupportClass.VectorRemoveElement(unsolicitedListeners, listener);
+                       return ;
+               }
+               
+               /// <summary>Inner class defined so that we can spawn off each unsolicited
+               /// listener as a seperate thread.  We did not want to call the
+               /// unsolicited listener method directly as this would have tied up our
+               /// deamon listener thread in the applications unsolicited listener method.
+               /// Since we do not know what the application unsolicited listener
+               /// might be doing and how long it will take to process the uncoslicited
+               /// notification.  We use this class to spawn off the unsolicited
+               /// notification as a separate thread
+               /// </summary>
+               private class UnsolicitedListenerThread:SupportClass.ThreadClass
+               {
+                       private void  InitBlock(Connection enclosingInstance)
+                       {
+                               this.enclosingInstance = enclosingInstance;
+                       }
+                       private Connection enclosingInstance;
+                       public Connection Enclosing_Instance
+                       {
+                               get
+                               {
+                                       return enclosingInstance;
+                               }
+                               
+                       }
+                       private LdapUnsolicitedNotificationListener listenerObj;
+                       private LdapExtendedResponse unsolicitedMsg;
+                       
+                       /* package */
+                       internal UnsolicitedListenerThread(Connection enclosingInstance, LdapUnsolicitedNotificationListener l, LdapExtendedResponse m)
+                       {
+                               InitBlock(enclosingInstance);
+                               this.listenerObj = l;
+                               this.unsolicitedMsg = m;
+                               return ;
+                       }
+                       
+                       public override void  Run()
+                       {
+                               listenerObj.messageReceived(unsolicitedMsg);
+                               return ;
+                       }
+               }
+               
+               private void  notifyAllUnsolicitedListeners(RfcLdapMessage message)
+               {
+                       
+                       
+                       // MISSING:  If this is a shutdown notification from the server
+                       // set a flag in the Connection class so that we can throw an
+                       // appropriate LdapException to the application
+                       LdapMessage extendedLdapMessage = new LdapExtendedResponse(message);
+                       System.String notificationOID = ((LdapExtendedResponse) extendedLdapMessage).ID;
+                       if (notificationOID.Equals(LdapConnection.SERVER_SHUTDOWN_OID))
+                       {
+                               
+                               
+                               unsolSvrShutDnNotification = true;
+                       }
+                       
+                       int numOfListeners = unsolicitedListeners.Count;
+                       
+                       // Cycle through all the listeners
+                       for (int i = 0; i < numOfListeners; i++)
+                       {
+                               
+                               // Get next listener
+                               LdapUnsolicitedNotificationListener listener = (LdapUnsolicitedNotificationListener) unsolicitedListeners[i];
+                               
+                               
+                               // Create a new ExtendedResponse each time as we do not want each listener
+                               // to have its own copy of the message
+                               LdapExtendedResponse tempLdapMessage = new LdapExtendedResponse(message);
+                               
+                               // Spawn a new thread for each listener to go process the message
+                               // The reason we create a new thread rather than just call the
+                               // the messageReceived method directly is beacuse we do not know
+                               // what kind of processing the notification listener class will
+                               // do.  We do not want our deamon thread to block waiting for
+                               // the notification listener method to return.
+                               UnsolicitedListenerThread u = new UnsolicitedListenerThread(this, listener, tempLdapMessage);
+                               u.Start();
+                       }
+                       
+                       
+                       return ;
+               }
+               static Connection()
+               {
+                       nameLock = new System.Object();
+                       sdk = new System.Text.StringBuilder("3.0").ToString();
+                       protocol = 3;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/InterThreadException.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/InterThreadException.cs
new file mode 100755 (executable)
index 0000000..f7c7762
--- /dev/null
@@ -0,0 +1,147 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.InterThreadException.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /* package */
+       public class InterThreadException:LdapException
+       {
+               /// <summary> Returns the message ID of this message request.
+               /// 
+               /// </summary>
+               /// <returns> the message ID.  Returns -1 if no message
+               /// is associated with this exception.
+               /// </returns>
+               virtual internal int MessageID
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               if (request == null)
+                               {
+                                       return - 1;
+                               }
+                               return request.MessageID;
+                       }
+                       
+               }
+               /// <summary> Returns the message type expected as a reply to
+               /// the message associated with this message's request type.
+               /// 
+               /// </summary>
+               /// <returns> the message type of the expected reply.  Returns -1
+               /// if no reply expected.
+               /// </returns>
+               virtual internal int ReplyType
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               if (request == null)
+                               {
+                                       return - 1;
+                               }
+                               int reqType = request.MessageType;
+                               int responseType = - 1;
+                               switch (reqType)
+                               {
+                                       
+                                       case LdapMessage.BIND_REQUEST: 
+                                               responseType = LdapMessage.BIND_RESPONSE;
+                                               break;
+                                       
+                                       case LdapMessage.UNBIND_REQUEST: 
+                                               responseType = - 1;
+                                               break;
+                                       
+                                       case LdapMessage.SEARCH_REQUEST: 
+                                               responseType = LdapMessage.SEARCH_RESULT;
+                                               break;
+                                       
+                                       case LdapMessage.MODIFY_REQUEST: 
+                                               responseType = LdapMessage.MODIFY_RESPONSE;
+                                               break;
+                                       
+                                       case LdapMessage.ADD_REQUEST: 
+                                               responseType = LdapMessage.ADD_RESPONSE;
+                                               break;
+                                       
+                                       case LdapMessage.DEL_REQUEST: 
+                                               responseType = LdapMessage.DEL_RESPONSE;
+                                               break;
+                                       
+                                       case LdapMessage.MODIFY_RDN_REQUEST: 
+                                               responseType = LdapMessage.MODIFY_RDN_RESPONSE;
+                                               break;
+                                       
+                                       case LdapMessage.COMPARE_REQUEST: 
+                                               responseType = LdapMessage.COMPARE_RESPONSE;
+                                               break;
+                                       
+                                       case LdapMessage.ABANDON_REQUEST: 
+                                               responseType = - 1;
+                                               break;
+                                       
+                                       case LdapMessage.EXTENDED_REQUEST: 
+                                               responseType = LdapMessage.EXTENDED_RESPONSE;
+                                               break;
+                                               
+                                       }
+                               return responseType;
+                       }
+                       
+               }
+               private Message request;
+               
+               /// <summary> Constructs a InterThreadException with its associated message.
+               /// 
+               /// </summary>
+               /// <param name="message">       The text providign additional error information.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">    The error result code.
+               /// <br><br>
+               /// </param>
+               /// <param name="request">       The Message class associated with this exception.
+               /// </param>
+               /* package */
+               internal InterThreadException(System.String message, System.Object[] arguments, int resultCode, System.Exception rootException, Message request):base(message, arguments, resultCode, (System.String) null, rootException)
+               {
+                       this.request = request;
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAbandonRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAbandonRequest.cs
new file mode 100755 (executable)
index 0000000..f56da7e
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapAbandonRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap Abandon Request
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso> 
+   /*
+       *       AbandonRequest ::= [APPLICATION 16] MessageID
+       */
+       public class LdapAbandonRequest:LdapMessage
+       {
+               /// <summary> Construct an Ldap Abandon Request.
+               /// <br><br>
+               /// </summary>
+               /// <param name="id">The ID of the operation to abandon.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">Any controls that apply to the abandon request
+               /// or null if none.
+               /// </param>
+               public LdapAbandonRequest(int id, LdapControl[] cont):base(LdapMessage.ABANDON_REQUEST, new RfcAbandonRequest(id), cont)
+               {
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAddRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAddRequest.cs
new file mode 100755 (executable)
index 0000000..1ce0a48
--- /dev/null
@@ -0,0 +1,132 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapAddRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap Add Request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso>
+   /*
+       *       AddRequest ::= [APPLICATION 8] SEQUENCE {
+       *               entry           LdapDN,
+       *               attributes      AttributeList }
+       */
+       public class LdapAddRequest:LdapMessage
+       {
+               /// <summary> Constructs an LdapEntry that represents the add request
+               /// 
+               /// </summary>
+               /// <returns> an LdapEntry that represents the add request.
+               /// </returns>
+               virtual public LdapEntry Entry
+               {
+                       get
+                       {
+                               RfcAddRequest addreq = (RfcAddRequest) Asn1Object.getRequest();
+                               
+                               LdapAttributeSet attrs = new LdapAttributeSet();
+                               
+                               // Build the list of attributes
+                               Asn1Object[] seqArray = addreq.Attributes.toArray();
+                               for (int i = 0; i < seqArray.Length; i++)
+                               {
+                                       RfcAttributeTypeAndValues seq = (RfcAttributeTypeAndValues) seqArray[i];
+                                       LdapAttribute attr = new LdapAttribute(((Asn1OctetString) seq.get_Renamed(0)).stringValue());
+                                       
+                                       // Add the values to the attribute
+                                       Asn1SetOf set_Renamed = (Asn1SetOf) seq.get_Renamed(1);
+                                       System.Object[] setArray = set_Renamed.toArray();
+                                       for (int j = 0; j < setArray.Length; j++)
+                                       {
+                                               attr.addValue(((Asn1OctetString) setArray[j]).byteValue());
+                                       }
+                                       attrs.Add(attr);
+                               }
+                               
+                               return new LdapEntry(Asn1Object.RequestDN, attrs);
+                       }
+                       
+               }
+               /// <summary> Constructs a request to add an entry to the directory.
+               /// 
+               /// </summary>
+               /// <param name="entry">The LdapEntry to add to the directory.
+               /// 
+               /// </param>
+               /// <param name="cont">Any controls that apply to the add request,
+               /// or null if none.
+               /// </param>
+               public LdapAddRequest(LdapEntry entry, LdapControl[] cont):base(LdapMessage.ADD_REQUEST, new RfcAddRequest(new RfcLdapDN(entry.DN), makeRfcAttrList(entry)), cont)
+               {
+                       return ;
+               }
+               
+               /// <summary> Build the attribuite list from an LdapEntry.
+               /// 
+               /// </summary>
+               /// <param name="entry">The LdapEntry associated with this add request.
+               /// </param>
+               private static RfcAttributeList makeRfcAttrList(LdapEntry entry)
+               {
+                       // convert Java-API LdapEntry to RFC2251 AttributeList
+                       LdapAttributeSet attrSet = entry.getAttributeSet();
+                       RfcAttributeList attrList = new RfcAttributeList(attrSet.Count);
+                       System.Collections.IEnumerator itr = attrSet.GetEnumerator();
+                       while (itr.MoveNext())
+                       {
+                               LdapAttribute attr = (LdapAttribute) itr.Current;
+                               Asn1SetOf vals = new Asn1SetOf(attr.size());
+                               System.Collections.IEnumerator attrEnum = attr.ByteValues;
+                               while (attrEnum.MoveNext())
+                               {
+                                       vals.add(new RfcAttributeValue((sbyte[]) attrEnum.Current));
+                               }
+                               attrList.add(new RfcAttributeTypeAndValues(new RfcAttributeDescription(attr.Name), vals));
+                       }
+                       return attrList;
+               }
+               
+               /// <summary> Return an Asn1 representation of this add request.
+               /// 
+               /// #return an Asn1 representation of this object.
+               /// </summary>
+               public override System.String ToString()
+               {
+                       return Asn1Object.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAttribute.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAttribute.cs
new file mode 100755 (executable)
index 0000000..77afb4f
--- /dev/null
@@ -0,0 +1,1068 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapAttribute.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using ArrayEnumeration = Novell.Directory.Ldap.Utilclass.ArrayEnumeration;
+using Base64 = Novell.Directory.Ldap.Utilclass.Base64;
+
+namespace Novell.Directory.Ldap
+{
+       /// <summary> The name and values of one attribute of a directory entry.
+       /// 
+       /// <p>LdapAttribute objects are used when searching for, adding,
+       /// modifying, and deleting attributes from the directory.
+       /// LdapAttributes are often used in conjunction with an
+       /// {@link LdapAttributeSet} when retrieving or adding multiple
+       /// attributes to an entry.
+       /// 
+       /// 
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapEntry">
+       /// </seealso>
+       /// <seealso cref="LdapAttributeSet">
+       /// </seealso>
+       /// <seealso cref="LdapModification">
+       /// </seealso>
+       
+       public class LdapAttribute : System.ICloneable, System.IComparable
+       {
+               class URLData
+               {
+                       private void  InitBlock(LdapAttribute enclosingInstance)
+                       {
+                               this.enclosingInstance = enclosingInstance;
+                       }
+                       private LdapAttribute enclosingInstance;
+                       public LdapAttribute Enclosing_Instance
+                       {
+                               get
+                               {
+                                       return enclosingInstance;
+                               }
+                               
+                       }
+                       private int length;
+                       private sbyte[] data;
+                       public URLData(LdapAttribute enclosingInstance, sbyte[] data, int length)
+                       {
+                               InitBlock(enclosingInstance);
+                               this.length = length;
+                               this.data = data;
+                               return ;
+                       }
+                       public int getLength()
+                       {
+                               return length;
+                       }
+                       public sbyte[] getData()
+                       {
+                               return data;
+                       }
+               }
+               /// <summary> Returns an enumerator for the values of the attribute in byte format.
+               /// 
+               /// </summary>
+               /// <returns> The values of the attribute in byte format.
+               /// <P> Note: All string values will be UTF-8 encoded. To decode use the
+               /// String constructor. Example: new String( byteArray, "UTF-8" );
+               /// </returns>
+               virtual public System.Collections.IEnumerator ByteValues
+               {
+                       get
+                       {
+                               return new ArrayEnumeration(ByteValueArray);
+                       }
+                       
+               }
+               /// <summary> Returns an enumerator for the string values of an attribute.
+               /// 
+               /// </summary>
+               /// <returns> The string values of an attribute.
+               /// </returns>
+               virtual public System.Collections.IEnumerator StringValues
+               {
+                       get
+                       {
+                               return new ArrayEnumeration(StringValueArray);
+                       }
+                       
+               }
+               /// <summary> Returns the values of the attribute as an array of bytes.
+               /// 
+               /// </summary>
+               /// <returns> The values as an array of bytes or an empty array if there are
+               /// no values.
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               virtual public sbyte[][] ByteValueArray
+               {
+                       get
+                       {
+                               if (null == this.values)
+                                       return new sbyte[0][];
+                               int size = this.values.Length;
+                               sbyte[][] bva = new sbyte[size][];
+                               // Deep copy so application cannot change values
+                               for (int i = 0, u = size; i < u; i++)
+                               {
+                                       bva[i] = new sbyte[((sbyte[]) values[i]).Length];
+                                       Array.Copy((System.Array) this.values[i], 0, (System.Array) bva[i], 0, bva[i].Length);
+                               }
+                               return bva;
+                       }
+                       
+               }
+               /// <summary> Returns the values of the attribute as an array of strings.
+               /// 
+               /// </summary>
+               /// <returns> The values as an array of strings or an empty array if there are
+               /// no values
+               /// </returns>
+               virtual public System.String[] StringValueArray
+               {
+                       get
+                       {
+                               if (null == this.values)
+                                       return new System.String[0];
+                               int size = values.Length;
+                               System.String[] sva = new System.String[size];
+                               for (int j = 0; j < size; j++)
+                               {
+                                       try
+                                       {
+                                               System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                                               char[] dchar = encoder.GetChars(SupportClass.ToByteArray((sbyte[])values[j]));
+//                                             char[] dchar = encoder.GetChars((byte[])values[j]);
+                                               sva[j] = new String(dchar);
+//                                             sva[j] = new String((sbyte[]) values[j], "UTF-8");
+                                       }
+                                       catch (System.IO.IOException uee)
+                                       {
+                                               // Exception should NEVER get thrown but just in case it does ...
+                                               throw new System.SystemException(uee.ToString());
+                                       }
+                               }
+                               return sva;
+                       }
+                       
+               }
+               /// <summary> Returns the the first value of the attribute as a <code>String</code>.
+               /// 
+               /// </summary>
+               /// <returns>  The UTF-8 encoded<code>String</code> value of the attribute's
+               /// value.  If the value wasn't a UTF-8 encoded <code>String</code>
+               /// to begin with the value of the returned <code>String</code> is
+               /// non deterministic.
+               /// 
+               /// <p>If <code>this</code> attribute has more than one value the
+               /// first value is converted to a UTF-8 encoded <code>String</code>
+               /// and returned. It should be noted, that the directory may
+               /// return attribute values in any order, so that the first
+               /// value may vary from one call to another.
+               /// 
+               /// <p>If the attribute has no values <code>null</code> is returned
+               /// </returns>
+               virtual public System.String StringValue
+               {
+                       get
+                       {
+                               System.String rval = null;
+                               if (this.values != null)
+                               {
+                                       try
+                                       {
+                                               System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                                               char[] dchar = encoder.GetChars(SupportClass.ToByteArray((sbyte[])this.values[0]));
+//                                             char[] dchar = encoder.GetChars((byte[]) this.values[0]);
+                                               rval = new String(dchar);
+                                       }
+                                       catch (System.IO.IOException use)
+                                       {
+                                               throw new System.SystemException(use.ToString());
+                                       }
+                               }
+                               return rval;
+                       }
+                       
+               }
+               /// <summary> Returns the the first value of the attribute as a byte array.
+               /// 
+               /// </summary>
+               /// <returns>  The binary value of <code>this</code> attribute or
+               /// <code>null</code> if <code>this</code> attribute doesn't have a value.
+               /// 
+               /// <p>If the attribute has no values <code>null</code> is returned
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               virtual public sbyte[] ByteValue
+               {
+                       get
+                       {
+                               sbyte[] bva = null;
+                               if (this.values != null)
+                               {
+                                       // Deep copy so app can't change the value
+                                       bva = new sbyte[((sbyte[]) values[0]).Length];
+                                       Array.Copy((System.Array) this.values[0], 0, (System.Array) bva, 0, bva.Length);
+                               }
+                               return bva;
+                       }
+                       
+               }
+               /// <summary> Returns the language subtype of the attribute, if any.
+               /// 
+               /// <p>For example, if the attribute name is cn;lang-ja;phonetic,
+               /// this method returns the string, lang-ja.</p>
+               /// 
+               /// </summary>
+               /// <returns> The language subtype of the attribute or null if the attribute
+               /// has none.
+               /// </returns>
+               virtual public System.String LangSubtype
+               {
+                       get
+                       {
+                               if (subTypes != null)
+                               {
+                                       for (int i = 0; i < subTypes.Length; i++)
+                                       {
+                                               if (subTypes[i].StartsWith("lang-"))
+                                               {
+                                                       return subTypes[i];
+                                               }
+                                       }
+                               }
+                               return null;
+                       }
+                       
+               }
+               /// <summary> Returns the name of the attribute.
+               /// 
+               /// </summary>
+               /// <returns> The name of the attribute.
+               /// </returns>
+               virtual public System.String Name
+               {
+                       get
+                       {
+                               return name;
+                       }
+                       
+               }
+               /// <summary> Replaces all values with the specified value. This protected method is
+               /// used by sub-classes of LdapSchemaElement because the value cannot be set
+               /// with a contructor.
+               /// </summary>
+               virtual protected internal System.String Value
+               {
+                       set
+                       {
+                               values = null;
+                               try
+                               {
+                                       System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                                       byte[] ibytes = encoder.GetBytes(value);
+                                       sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
+
+                                       this.add(sbytes);
+                               }
+                               catch (System.IO.IOException ue)
+                               {
+                                       throw new System.SystemException(ue.ToString());
+                               }
+                               return ;
+                       }
+                       
+               }
+               private System.String name; // full attribute name
+               private System.String baseName; // cn of cn;lang-ja;phonetic
+               private System.String[] subTypes = null; // lang-ja of cn;lang-ja
+               private System.Object[] values = null; // Array of byte[] attribute values
+               
+               /// <summary> Constructs an attribute with copies of all values of the input
+               /// attribute.
+               /// 
+               /// </summary>
+               /// <param name="attr"> An LdapAttribute to use as a template.
+               /// 
+               /// @throws IllegalArgumentException if attr is null
+               /// </param>
+               public LdapAttribute(LdapAttribute attr)
+               {
+                       if (attr == null)
+                       {
+                               throw new System.ArgumentException("LdapAttribute class cannot be null");
+                       }
+                       // Do a deep copy of the LdapAttribute template
+                       this.name = attr.name;
+                       this.baseName = attr.baseName;
+                       if (null != attr.subTypes)
+                       {
+                               this.subTypes = new System.String[attr.subTypes.Length];
+                               Array.Copy((System.Array) attr.subTypes, 0, (System.Array) this.subTypes, 0, this.subTypes.Length);
+                       }
+                       // OK to just copy attributes, as the app only sees a deep copy of them
+                       if (null != attr.values)
+                       {
+                               this.values = new System.Object[attr.values.Length];
+                               Array.Copy((System.Array) attr.values, 0, (System.Array) this.values, 0, this.values.Length);
+                       }
+                       return ;
+               }
+               
+               /// <summary> Constructs an attribute with no values.
+               /// 
+               /// </summary>
+               /// <param name="attrName">Name of the attribute.
+               /// 
+               /// @throws IllegalArgumentException if attrName is null
+               /// </param>
+               public LdapAttribute(System.String attrName)
+               {
+                       if ((System.Object) attrName == null)
+                       {
+                               throw new System.ArgumentException("Attribute name cannot be null");
+                       }
+                       this.name = attrName;
+                       this.baseName = LdapAttribute.getBaseName(attrName);
+                       this.subTypes = LdapAttribute.getSubtypes(attrName);
+                       return ;
+               }
+               
+               /// <summary> Constructs an attribute with a byte-formatted value.
+               /// 
+               /// </summary>
+               /// <param name="attrName">Name of the attribute.<br><br>
+               /// </param>
+               /// <param name="attrBytes">Value of the attribute as raw bytes.
+               /// 
+               /// <P> Note: If attrBytes represents a string it should be UTF-8 encoded.
+               /// 
+               /// @throws IllegalArgumentException if attrName or attrBytes is null
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public LdapAttribute(System.String attrName, sbyte[] attrBytes):this(attrName)
+               {
+                       if (attrBytes == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       // Make our own copy of the byte array to prevent app from changing it
+                       sbyte[] tmp = new sbyte[attrBytes.Length];
+                       Array.Copy((System.Array) attrBytes, 0, (System.Array)tmp, 0, attrBytes.Length);
+                       this.add(tmp);
+                       return ;
+               }
+               
+               /// <summary> Constructs an attribute with a single string value.
+               /// 
+               /// </summary>
+               /// <param name="attrName">Name of the attribute.<br><br>
+               /// </param>
+               /// <param name="attrString">Value of the attribute as a string.
+               /// 
+               /// @throws IllegalArgumentException if attrName or attrString is null
+               /// </param>
+               public LdapAttribute(System.String attrName, System.String attrString):this(attrName)
+               {
+                       if ((System.Object) attrString == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       try
+                       {
+                               System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                               byte[] ibytes = encoder.GetBytes(attrString);
+                               sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
+
+                               this.add(sbytes);
+                       }
+                       catch (System.IO.IOException e)
+                       {
+                               throw new System.SystemException(e.ToString());
+                       }
+                       return ;
+               }
+               
+               /// <summary> Constructs an attribute with an array of string values.
+               /// 
+               /// </summary>
+               /// <param name="attrName">Name of the attribute.<br><br>
+               /// </param>
+               /// <param name="attrStrings">Array of values as strings.
+               /// 
+               /// @throws IllegalArgumentException if attrName, attrStrings, or a member
+               /// of attrStrings is null
+               /// </param>
+               public LdapAttribute(System.String attrName, System.String[] attrStrings):this(attrName)
+               {
+                       if (attrStrings == null)
+                       {
+                               throw new System.ArgumentException("Attribute values array cannot be null");
+                       }
+                       for (int i = 0, u = attrStrings.Length; i < u; i++)
+                       {
+                               try
+                               {
+                                       if ((System.Object) attrStrings[i] == null)
+                                       {
+                                               throw new System.ArgumentException("Attribute value " + "at array index " + i + " cannot be null");
+                                       }
+                                       System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                                       byte[] ibytes = encoder.GetBytes(attrStrings[i]);
+                                       sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
+                                       this.add(sbytes);
+//                                     this.add(attrStrings[i].getBytes("UTF-8"));
+                               }
+                               catch (System.IO.IOException e)
+                               {
+                                       throw new System.SystemException(e.ToString());
+                               }
+                       }
+                       return ;
+               }
+               
+               /// <summary> Returns a clone of this LdapAttribute.
+               /// 
+               /// </summary>
+               /// <returns> clone of this LdapAttribute.
+               /// </returns>
+               public System.Object Clone()
+               {
+                       try
+                       {
+                               System.Object newObj = base.MemberwiseClone();
+                               if (values != null)
+                               {
+                                       Array.Copy((System.Array) this.values, 0, (System.Array) ((LdapAttribute) newObj).values, 0, this.values.Length);
+                               }
+                               return newObj;
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+               }
+               
+               /// <summary> Adds a string value to the attribute.
+               /// 
+               /// </summary>
+               /// <param name="attrString">Value of the attribute as a String.
+               /// 
+               /// @throws IllegalArgumentException if attrString is null
+               /// </param>
+               public virtual void  addValue(System.String attrString)
+               {
+                       if ((System.Object) attrString == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       try
+                       {
+                               System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                               byte[] ibytes = encoder.GetBytes(attrString);
+                               sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
+                               this.add(sbytes);
+//                             this.add(attrString.getBytes("UTF-8"));
+                       }
+                       catch (System.IO.IOException ue)
+                       {
+                               throw new System.SystemException(ue.ToString());
+                       }
+                       return ;
+               }
+               
+               /// <summary> Adds a byte-formatted value to the attribute.
+               /// 
+               /// </summary>
+               /// <param name="attrBytes">Value of the attribute as raw bytes.
+               /// 
+               /// <P> Note: If attrBytes represents a string it should be UTF-8 encoded.
+               /// 
+               /// @throws IllegalArgumentException if attrBytes is null
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public virtual void  addValue(sbyte[] attrBytes)
+               {
+                       if (attrBytes == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       this.add(attrBytes);
+                       return ;
+               }
+               
+               /// <summary> Adds a base64 encoded value to the attribute.
+               /// The value will be decoded and stored as bytes.  String
+               /// data encoded as a base64 value must be UTF-8 characters.
+               /// 
+               /// </summary>
+               /// <param name="attrString">The base64 value of the attribute as a String.
+               /// 
+               /// @throws IllegalArgumentException if attrString is null
+               /// </param>
+               public virtual void  addBase64Value(System.String attrString)
+               {
+                       if ((System.Object) attrString == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       
+                       this.add(Base64.decode(attrString));
+                       return ;
+               }
+               
+               /// <summary> Adds a base64 encoded value to the attribute.
+               /// The value will be decoded and stored as bytes.  Character
+               /// data encoded as a base64 value must be UTF-8 characters.
+               /// 
+               /// </summary>
+               /// <param name="attrString">The base64 value of the attribute as a StringBuffer.
+               /// </param>
+               /// <param name="start"> The start index of base64 encoded part, inclusive.
+               /// </param>
+               /// <param name="end"> The end index of base encoded part, exclusive.
+               /// 
+               /// @throws IllegalArgumentException if attrString is null
+               /// </param>
+               public virtual void  addBase64Value(System.Text.StringBuilder attrString, int start, int end)
+               {
+                       if (attrString == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       
+                       this.add(Base64.decode(attrString, start, end));
+                       
+                       return ;
+               }
+               
+               /// <summary> Adds a base64 encoded value to the attribute.
+               /// The value will be decoded and stored as bytes.  Character
+               /// data encoded as a base64 value must be UTF-8 characters.
+               /// 
+               /// </summary>
+               /// <param name="attrChars">The base64 value of the attribute as an array of
+               /// characters.
+               /// 
+               /// @throws IllegalArgumentException if attrString is null
+               /// </param>
+               public virtual void  addBase64Value(char[] attrChars)
+               {
+                       if (attrChars == null)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       
+                       this.add(Base64.decode(attrChars));
+                       return ;
+               }
+               
+               /// <summary> Adds a URL, indicating a file or other resource that contains
+               /// the value of the attribute.
+               /// 
+               /// </summary>
+               /// <param name="url">String value of a URL pointing to the resource containing
+               /// the value of the attribute.
+               /// 
+               /// @throws IllegalArgumentException if url is null
+               /// </param>
+               public virtual void  addURLValue(System.String url)
+               {
+                       if ((System.Object) url == null)
+                       {
+                               throw new System.ArgumentException("Attribute URL cannot be null");
+                       }
+                       addURLValue(new System.Uri(url));
+                       return ;
+               }
+               
+               /// <summary> Adds a URL, indicating a file or other resource that contains
+               /// the value of the attribute.
+               /// 
+               /// </summary>
+               /// <param name="url">A URL class pointing to the resource containing the value
+               /// of the attribute.
+               /// 
+               /// @throws IllegalArgumentException if url is null
+               /// </param>
+               public virtual void  addURLValue(System.Uri url)
+               {
+                       // Class to encapsulate the data bytes and the length
+                       if (url == null)
+                       {
+                               throw new System.ArgumentException("Attribute URL cannot be null");
+                       }
+                       try
+                       {
+                               // Get InputStream from the URL
+                               System.IO.Stream in_Renamed = System.Net.WebRequest.Create(url).GetResponse().GetResponseStream();
+                               // Read the bytes into buffers and store the them in an arraylist
+                               System.Collections.ArrayList bufs = new System.Collections.ArrayList();
+                               sbyte[] buf = new sbyte[4096];
+                               int len, totalLength = 0;
+                               while ((len = SupportClass.ReadInput(in_Renamed, ref buf, 0, 4096)) != - 1)
+                               {
+                                       bufs.Add(new URLData(this, buf, len));
+                                       buf = new sbyte[4096];
+                                       totalLength += len;
+                               }
+                               /*
+                               * Now that the length is known, allocate an array to hold all
+                               * the bytes of data and copy the data to that array, store
+                               * it in this LdapAttribute
+                               */
+                               sbyte[] data = new sbyte[totalLength];
+                               int offset = 0; //
+                               for (int i = 0; i < bufs.Count; i++)
+                               {
+                                       URLData b = (URLData) bufs[i];
+                                       len = b.getLength();
+                                       Array.Copy((System.Array) b.getData(), 0, (System.Array) data, offset, len);
+                                       offset += len;
+                               }
+                               this.add(data);
+                       }
+                       catch (System.IO.IOException ue)
+                       {
+                               throw new System.SystemException(ue.ToString());
+                       }
+                       return ;
+               }
+               
+               /// <summary> Returns the base name of the attribute.
+               /// 
+               /// <p>For example, if the attribute name is cn;lang-ja;phonetic,
+               /// this method returns cn.</p>
+               /// 
+               /// </summary>
+               /// <returns> The base name of the attribute.
+               /// </returns>
+               public virtual System.String getBaseName()
+               {
+                       return baseName;
+               }
+               
+               /// <summary> Returns the base name of the specified attribute name.
+               /// 
+               /// <p>For example, if the attribute name is cn;lang-ja;phonetic,
+               /// this method returns cn.</p>
+               /// 
+               /// </summary>
+               /// <param name="attrName">Name of the attribute from which to extract the
+               /// base name.
+               /// 
+               /// </param>
+               /// <returns> The base name of the attribute.
+               /// 
+               /// @throws IllegalArgumentException if attrName is null
+               /// </returns>
+               public static System.String getBaseName(System.String attrName)
+               {
+                       if ((System.Object) attrName == null)
+                       {
+                               throw new System.ArgumentException("Attribute name cannot be null");
+                       }
+                       int idx = attrName.IndexOf((System.Char) ';');
+                       if (- 1 == idx)
+                       {
+                               return attrName;
+                       }
+                       return attrName.Substring(0, (idx) - (0));
+               }
+               
+               /// <summary> Extracts the subtypes from the attribute name.
+               /// 
+               /// <p>For example, if the attribute name is cn;lang-ja;phonetic,
+               /// this method returns an array containing lang-ja and phonetic.
+               /// 
+               /// </summary>
+               /// <returns> An array subtypes or null if the attribute has none.
+               /// </returns>
+               public virtual System.String[] getSubtypes()
+               {
+                       return subTypes;
+               }
+               
+               /// <summary> Extracts the subtypes from the specified attribute name.
+               /// 
+               /// <p>For example, if the attribute name is cn;lang-ja;phonetic,
+               /// this method returns an array containing lang-ja and phonetic.</p>
+               /// 
+               /// </summary>
+               /// <param name="attrName">  Name of the attribute from which to extract
+               /// the subtypes.
+               /// 
+               /// </param>
+               /// <returns> An array subtypes or null if the attribute has none.
+               /// 
+               /// @throws IllegalArgumentException if attrName is null
+               /// </returns>
+               public static System.String[] getSubtypes(System.String attrName)
+               {
+                       if ((System.Object) attrName == null)
+                       {
+                               throw new System.ArgumentException("Attribute name cannot be null");
+                       }
+                       SupportClass.Tokenizer st = new SupportClass.Tokenizer(attrName, ";");
+                       System.String[] subTypes = null;
+                       int cnt = st.Count;
+                       if (cnt > 0)
+                       {
+                               st.NextToken(); // skip over basename
+                               subTypes = new System.String[cnt - 1];
+                               int i = 0;
+                               while (st.HasMoreTokens())
+                               {
+                                       subTypes[i++] = st.NextToken();
+                               }
+                       }
+                       return subTypes;
+               }
+               
+               /// <summary> Reports if the attribute name contains the specified subtype.
+               /// 
+               /// <p>For example, if you check for the subtype lang-en and the
+               /// attribute name is cn;lang-en, this method returns true.</p>
+               /// 
+               /// </summary>
+               /// <param name="subtype"> The single subtype to check for.
+               /// 
+               /// </param>
+               /// <returns> True, if the attribute has the specified subtype;
+               /// false, if it doesn't.
+               /// 
+               /// @throws IllegalArgumentException if subtype is null
+               /// </returns>
+               public virtual bool hasSubtype(System.String subtype)
+               {
+                       if ((System.Object) subtype == null)
+                       {
+                               throw new System.ArgumentException("subtype cannot be null");
+                       }
+                       if (null != this.subTypes)
+                       {
+                               for (int i = 0; i < subTypes.Length; i++)
+                               {
+                                       if (subTypes[i].ToUpper().Equals(subtype.ToUpper()))
+                                               return true;
+                               }
+                       }
+                       return false;
+               }
+               
+               /// <summary> Reports if the attribute name contains all the specified subtypes.
+               /// 
+               /// <p> For example, if you check for the subtypes lang-en and phonetic
+               /// and if the attribute name is cn;lang-en;phonetic, this method
+               /// returns true. If the attribute name is cn;phonetic or cn;lang-en,
+               /// this method returns false.</p>
+               /// 
+               /// </summary>
+               /// <param name="subtypes">  An array of subtypes to check for.
+               /// 
+               /// </param>
+               /// <returns> True, if the attribute has all the specified subtypes;
+               /// false, if it doesn't have all the subtypes.
+               /// 
+               /// @throws IllegalArgumentException if subtypes is null or if array member
+               /// is null.
+               /// </returns>
+               public virtual bool hasSubtypes(System.String[] subtypes)
+               {
+                       if (subtypes == null)
+                       {
+                               throw new System.ArgumentException("subtypes cannot be null");
+                       }
+                       for (int i = 0; i < subtypes.Length; i++)
+                       {
+                               for (int j = 0; j < subTypes.Length; j++)
+                               {
+                                       if ((System.Object) subTypes[j] == null)
+                                       {
+                                               throw new System.ArgumentException("subtype " + "at array index " + i + " cannot be null");
+                                       }
+                                       if (subTypes[j].ToUpper().Equals(subtypes[i].ToUpper()))
+                                       {
+                                               goto gotSubType;
+                                       }
+                               }
+                               return false;
+gotSubType: ;
+                       }
+                       return true;
+               }
+               
+               /// <summary> Removes a string value from the attribute.
+               /// 
+               /// </summary>
+               /// <param name="attrString">  Value of the attribute as a string.
+               /// 
+               /// <p>Note: Removing a value which is not present in the attribute has
+               /// no effect.</p>
+               /// 
+               /// @throws IllegalArgumentException if attrString is null
+               /// </param>
+               public virtual void  removeValue(System.String attrString)
+               {
+                       if (null == (System.Object) attrString)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       try
+                       {
+                               System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                               byte[] ibytes = encoder.GetBytes(attrString);
+                               sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
+                               this.removeValue(sbytes);
+//                             this.removeValue(attrString.getBytes("UTF-8"));
+                       }
+                       catch (System.IO.IOException uee)
+                       {
+                               // This should NEVER happen but just in case ...
+                               throw new System.SystemException(uee.ToString());
+                       }
+                       return ;
+               }
+               
+               /// <summary> Removes a byte-formatted value from the attribute.
+               /// 
+               /// </summary>
+               /// <param name="attrBytes">   Value of the attribute as raw bytes.
+               /// <P> Note: If attrBytes represents a string it should be UTF-8 encoded.
+               /// Example: <code>String.getBytes("UTF-8");</code></P>
+               /// 
+               /// <p>Note: Removing a value which is not present in the attribute has
+               /// no effect.</p>
+               /// 
+               /// @throws IllegalArgumentException if attrBytes is null
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public virtual void  removeValue(sbyte[] attrBytes)
+               {
+                       if (null == attrBytes)
+                       {
+                               throw new System.ArgumentException("Attribute value cannot be null");
+                       }
+                       for (int i = 0; i < this.values.Length; i++)
+                       {
+                               if (equals(attrBytes, (sbyte[]) this.values[i]))
+                               {
+                                       if (0 == i && 1 == this.values.Length)
+                                       {
+                                               // Optimize if first element of a single valued attr
+                                               this.values = null;
+                                               return ;
+                                       }
+                                       if (this.values.Length == 1)
+                                       {
+                                               this.values = null;
+                                       }
+                                       else
+                                       {
+                                               int moved = this.values.Length - i - 1;
+                                               System.Object[] tmp = new System.Object[this.values.Length - 1];
+                                               if (i != 0)
+                                               {
+                                                       Array.Copy((System.Array) values, 0, (System.Array) tmp, 0, i);
+                                               }
+                                               if (moved != 0)
+                                               {
+                                                       Array.Copy((System.Array) values, i + 1, (System.Array) tmp, i, moved);
+                                               }
+                                               this.values = tmp;
+                                               tmp = null;
+                                       }
+                                       break;
+                               }
+                       }
+                       return ;
+               }
+               
+               /// <summary> Returns the number of values in the attribute.
+               /// 
+               /// </summary>
+               /// <returns> The number of values in the attribute.
+               /// </returns>
+               public virtual int size()
+               {
+                       return null == this.values?0:this.values.Length;
+               }
+               
+               /// <summary> Compares this object with the specified object for order.
+               /// 
+               /// <p> Ordering is determined by comparing attribute names (see
+               /// {@link #getName() }) using the method compareTo() of the String class.
+               /// </p>
+               /// 
+               /// </summary>
+               /// <param name="attribute">  The LdapAttribute to be compared to this object.
+               /// 
+               /// </param>
+               /// <returns>            Returns a negative integer, zero, or a positive
+               /// integer as this object is less than, equal to, or greater than the
+               /// specified object.
+               /// </returns>
+               public virtual int CompareTo(System.Object attribute)
+               {
+                       
+                       return name.CompareTo(((LdapAttribute) attribute).name);
+               }
+               
+               /// <summary> Adds an object to <code>this</code> object's list of attribute values
+               /// 
+               /// </summary>
+               /// <param name="bytes">  Ultimately all of this attribute's values are treated
+               /// as binary data so we simplify the process by requiring
+               /// that all data added to our list is in binary form.
+               /// 
+               /// <P> Note: If attrBytes represents a string it should be UTF-8 encoded.
+               /// </param>
+               private void  add(sbyte[] bytes)
+               {
+                       if (null == this.values)
+                       {
+                               this.values = new System.Object[]{bytes};
+                       }
+                       else
+                       {
+                               // Duplicate attribute values not allowed
+                               for (int i = 0; i < this.values.Length; i++)
+                               {
+                                       if (equals(bytes, (sbyte[]) this.values[i]))
+                                       {
+                                               return ; // Duplicate, don't add
+                                       }
+                               }
+                               System.Object[] tmp = new System.Object[this.values.Length + 1];
+                               Array.Copy((System.Array) this.values, 0, (System.Array) tmp, 0, this.values.Length);
+                               tmp[this.values.Length] = bytes;
+                               this.values = tmp;
+                               tmp = null;
+                       }
+                       return ;
+               }
+               
+               /// <summary> Returns true if the two specified arrays of bytes are equal to each
+               /// another.  Matches the logic of Arrays.equals which is not available
+               /// in jdk 1.1.x.
+               /// 
+               /// </summary>
+               /// <param name="e1">the first array to be tested
+               /// </param>
+               /// <param name="e2">the second array to be tested
+               /// </param>
+               /// <returns> true if the two arrays are equal
+               /// </returns>
+               private bool equals(sbyte[] e1, sbyte[] e2)
+               {
+                       // If same object, they compare true
+                       if (e1 == e2)
+                               return true;
+                       
+                       // If either but not both are null, they compare false
+                       if (e1 == null || e2 == null)
+                               return false;
+                       
+                       // If arrays have different length, they compare false
+                       int length = e1.Length;
+                       if (e2.Length != length)
+                               return false;
+                       
+                       // If any of the bytes are different, they compare false
+                       for (int i = 0; i < length; i++)
+                       {
+                               if (e1[i] != e2[i])
+                                       return false;
+                       }
+                       
+                       return true;
+               }
+               
+               /// <summary> Returns a string representation of this LdapAttribute
+               /// 
+               /// </summary>
+               /// <returns> a string representation of this LdapAttribute
+               /// </returns>
+               public override System.String ToString()
+               {
+                       System.Text.StringBuilder result = new System.Text.StringBuilder("LdapAttribute: ");
+                       try
+                       {
+                               result.Append("{type='" + name + "'");
+                               if (values != null)
+                               {
+                                       result.Append(", ");
+                                       if (values.Length == 1)
+                                       {
+                                               result.Append("value='");
+                                       }
+                                       else
+                                       {
+                                               result.Append("values='");
+                                       }
+                                       for (int i = 0; i < values.Length; i++)
+                                       {
+                                               if (i != 0)
+                                               {
+                                                       result.Append("','");
+                                               }
+                                               if (((sbyte[]) values[i]).Length == 0)
+                                               {
+                                                       continue;
+                                               }
+                                               System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+//                                             char[] dchar = encoder.GetChars((byte[]) values[i]);
+                                               char[] dchar = encoder.GetChars(SupportClass.ToByteArray((sbyte[])values[i]));
+                                               System.String sval = new String(dchar);
+
+//                                             System.String sval = new String((sbyte[]) values[i], "UTF-8");
+                                               if (sval.Length == 0)
+                                               {
+                                                       // didn't decode well, must be binary
+                                                       result.Append("<binary value, length:" + sval.Length);
+                                                       continue;
+                                               }
+                                               result.Append(sval);
+                                       }
+                                       result.Append("'");
+                               }
+                               result.Append("}");
+                       }
+                       catch (System.Exception e)
+                       {
+                               throw new System.SystemException(e.ToString());
+                       }
+                       return result.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAttributeSet.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAttributeSet.cs
new file mode 100755 (executable)
index 0000000..2a14da2
--- /dev/null
@@ -0,0 +1,426 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapAttributeSet.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// A set of {@link LdapAttribute} objects.
+       /// 
+       /// <p>An <code>LdapAttributeSet</code> is a collection of <code>LdapAttribute</code>
+       /// classes as returned from an <code>LdapEntry</code> on a search or read
+       /// operation. <code>LdapAttributeSet</code> may be also used to contruct an entry
+       /// to be added to a directory.  If the <code>add()</code> or <code>addAll()</code>
+       /// methods are called and one or more of the objects to be added is not
+       /// an <code>LdapAttribute, ClassCastException</code> is thrown (as discussed in the
+       /// documentation for <code>java.util.Collection</code>).
+       /// 
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapAttribute">
+       /// </seealso>
+       /// <seealso cref="LdapEntry">
+       /// </seealso>
+       public class LdapAttributeSet:SupportClass.AbstractSetSupport, System.ICloneable//, SupportClass.SetSupport
+       {
+               /// <summary> Returns the number of attributes in this set.
+               /// 
+               /// </summary>
+               /// <returns> number of attributes in this set.
+               /// </returns>
+               public override int Count
+               {
+                       get
+                       {
+                               return this.map.Count;
+                       }
+                       
+               }
+               
+               /// <summary> This is the underlying data structure for this set.
+               /// <p>HashSet is similar to the functionality of this set.  The difference
+               /// is we use the name of an attribute as keys in the Map and LdapAttributes
+               /// as the values.  We also do not declare the map as transient, making the
+               /// map serializable.</p>
+               /// </summary>
+               private System.Collections.Hashtable map;
+               
+               /// <summary> Constructs an empty set of attributes.</summary>
+               public LdapAttributeSet():base()
+               {
+                       map = new System.Collections.Hashtable();
+               }
+               
+               // ---  methods not defined in Set ---
+               
+               /// <summary> Returns a deep copy of this attribute set.
+               /// 
+               /// </summary>
+               /// <returns> A deep copy of this attribute set.
+               /// </returns>
+               public override System.Object Clone()
+               {
+                       try
+                       {
+                               System.Object newObj = base.MemberwiseClone();
+                               System.Collections.IEnumerator i = this.GetEnumerator();
+                               while (i.MoveNext())
+                               {
+                                       ((LdapAttributeSet) newObj).Add(((LdapAttribute) i.Current).Clone());
+                               }
+                               return newObj;
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+               }
+               
+               /// <summary> Returns the attribute matching the specified attrName.
+               /// 
+               /// <p>For example:</p>
+               /// <ul>
+               /// <li><code>getAttribute("cn")</code>      returns only the "cn" attribute</li>
+               /// <li><code>getAttribute("cn;lang-en")</code> returns only the "cn;lang-en"
+               /// attribute.</li>
+               /// </ul>
+               /// <p>In both cases, <code>null</code> is returned if there is no exact match to
+               /// the specified attrName.</p>
+               /// 
+               /// <p>Note: Novell eDirectory does not currently support language subtypes.
+               /// It does support the "binary" subtype.</p>
+               /// 
+               /// </summary>
+               /// <param name="attrName">  The name of an attribute to retrieve, with or without
+               /// subtype specifications. For example, "cn", "cn;phonetic", and
+               /// "cn;binary" are valid attribute names.
+               /// 
+               /// </param>
+               /// <returns> The attribute matching the specified attrName, or <code>null</code>
+               /// if there is no exact match.
+               /// </returns>
+               public virtual LdapAttribute getAttribute(System.String attrName)
+               {
+                       return (LdapAttribute) map[attrName.ToUpper()];
+               }
+               
+               /// <summary> Returns a single best-match attribute, or <code>null</code> if no match is
+               /// available in the entry.
+               /// 
+               /// <p>Ldap version 3 allows adding a subtype specification to an attribute
+               /// name. For example, "cn;lang-ja" indicates a Japanese language
+               /// subtype of the "cn" attribute and "cn;lang-ja-JP-kanji" may be a subtype
+               /// of "cn;lang-ja". This feature may be used to provide multiple
+               /// localizations in the same directory. For attributes which do not vary
+               /// among localizations, only the base attribute may be stored, whereas
+               /// for others there may be varying degrees of specialization.</p>
+               /// 
+               /// <p>For example, <code>getAttribute(attrName,lang)</code> returns the
+               /// <code>LdapAttribute</code> that exactly matches attrName and that
+               /// best matches lang.</p>
+               /// 
+               /// <p>If there are subtypes other than "lang" subtypes included
+               /// in attrName, for example, "cn;binary", only attributes with all of
+               /// those subtypes are returned. If lang is <code>null</code> or empty, the
+               /// method behaves as getAttribute(attrName). If there are no matching
+               /// attributes, <code>null</code> is returned. </p>
+               /// 
+               /// 
+               /// <p>Assume the entry contains only the following attributes:</p>
+               /// 
+               /// <ul>
+               /// <li>cn;lang-en</li>
+               /// <li>cn;lang-ja-JP-kanji</li>
+               /// <li>sn</li>
+               /// </ul>
+               /// 
+               /// <p>Examples:</p>
+               /// <ul>
+               /// <li><code>getAttribute( "cn" )</code>       returns <code>null</code>.</li>
+               /// <li><code>getAttribute( "sn" )</code>       returns the "sn" attribute.</li>
+               /// <li><code>getAttribute( "cn", "lang-en-us" )</code>
+               /// returns the "cn;lang-en" attribute.</li>
+               /// <li><code>getAttribute( "cn", "lang-en" )</code>
+               /// returns the "cn;lang-en" attribute.</li>
+               /// <li><code>getAttribute( "cn", "lang-ja" )</code>
+               /// returns <code>null</code>.</li>
+               /// <li><code>getAttribute( "sn", "lang-en" )</code>
+               /// returns the "sn" attribute.</li>
+               /// </ul>
+               /// 
+               /// <p>Note: Novell eDirectory does not currently support language subtypes.
+               /// It does support the "binary" subtype.</p>
+               /// 
+               /// </summary>
+               /// <param name="attrName"> The name of an attribute to retrieve, with or without
+               /// subtype specifications. For example, "cn", "cn;phonetic", and
+               /// cn;binary" are valid attribute names.
+               /// <br><br>
+               /// </param>
+               /// <param name="lang">  A language specification with optional subtypes
+               /// appended using "-" as separator. For example, "lang-en", "lang-en-us",
+               /// "lang-ja", and "lang-ja-JP-kanji" are valid language specification.
+               /// 
+               /// </param>
+               /// <returns> A single best-match <code>LdapAttribute</code>, or <code>null</code>
+               /// if no match is found in the entry.
+               /// 
+               /// </returns>
+               public virtual LdapAttribute getAttribute(System.String attrName, System.String lang)
+               {
+                       System.String key = attrName + ";" + lang;
+                       return (LdapAttribute) map[key.ToUpper()];
+               }
+               
+               /// <summary> Creates a new attribute set containing only the attributes that have
+               /// the specified subtypes.
+               /// 
+               /// <p>For example, suppose an attribute set contains the following
+               /// attributes:</p>
+               /// 
+               /// <ul>
+               /// <li>    cn</li>
+               /// <li>    cn;lang-ja</li>
+               /// <li>    sn;phonetic;lang-ja</li>
+               /// <li>    sn;lang-us</li>
+               /// </ul>
+               /// 
+               /// <p>Calling the <code>getSubset</code> method and passing lang-ja as the
+               /// argument, the method returns an attribute set containing the following
+               /// attributes:</p>
+               /// 
+               /// <ul>
+               /// <li>cn;lang-ja</li>
+               /// <li>sn;phonetic;lang-ja</li>
+               /// </ul>
+               /// 
+               /// </summary>
+               /// <param name="subtype">   Semi-colon delimited list of subtypes to include. For
+               /// example:
+               /// <ul>
+               /// <li> "lang-ja" specifies only Japanese language subtypes</li>
+               /// <li> "binary" specifies only binary subtypes</li>
+               /// <li> "binary;lang-ja" specifies only Japanese language subtypes
+               /// which also are binary</li>
+               /// </ul>
+               /// 
+               /// <p>Note: Novell eDirectory does not currently support language subtypes.
+               /// It does support the "binary" subtype.</p>
+               /// 
+               /// </param>
+               /// <returns> An attribute set containing the attributes that match the
+               /// specified subtype.
+               /// </returns>
+               public virtual LdapAttributeSet getSubset(System.String subtype)
+               {
+                       
+                       // Create a new tempAttributeSet
+                       LdapAttributeSet tempAttributeSet = new LdapAttributeSet();
+                       System.Collections.IEnumerator i = this.GetEnumerator();
+                       
+                       // Cycle throught this.attributeSet
+                       while (i.MoveNext())
+                       {
+                               LdapAttribute attr = (LdapAttribute) i.Current;
+                               
+                               // Does this attribute have the subtype we are looking for. If
+                               // yes then add it to our AttributeSet, else next attribute
+                               if (attr.hasSubtype(subtype))
+                                       tempAttributeSet.Add(attr.Clone());
+                       }
+                       return tempAttributeSet;
+               }
+               
+               // --- methods defined in set ---
+               
+               /// <summary> Returns an iterator over the attributes in this set.  The attributes
+               /// returned from this iterator are not in any particular order.
+               /// 
+               /// </summary>
+               /// <returns> iterator over the attributes in this set
+               /// </returns>
+               public  override  System.Collections.IEnumerator GetEnumerator()
+               {
+                       return this.map.Values.GetEnumerator();
+               }
+               
+               /// <summary> Returns <code>true</code> if this set contains no elements
+               /// 
+               /// </summary>
+               /// <returns> <code>true</code> if this set contains no elements
+               /// </returns>
+               public override bool IsEmpty()
+               {
+                       return (this.map.Count == 0);
+               }
+               
+               /// <summary> Returns <code>true</code> if this set contains an attribute of the same name
+               /// as the specified attribute.
+               /// 
+               /// </summary>
+               /// <param name="attr">  Object of type <code>LdapAttribute</code>
+               /// 
+               /// </param>
+               /// <returns> true if this set contains the specified attribute
+               /// 
+               /// @throws ClassCastException occurs the specified Object
+               /// is not of type LdapAttribute.
+               /// </returns>
+               public override bool Contains(object attr)
+               {
+                       LdapAttribute attribute = (LdapAttribute) attr;
+                       return this.map.ContainsKey(attribute.Name.ToUpper());
+               }
+               
+               /// <summary> Adds the specified attribute to this set if it is not already present.
+               /// <p>If an attribute with the same name already exists in the set then the
+               /// specified attribute will not be added.</p>
+               /// 
+               /// </summary>
+               /// <param name="attr">  Object of type <code>LdapAttribute</code>
+               /// 
+               /// </param>
+               /// <returns> true if the attribute was added.
+               /// 
+               /// @throws ClassCastException occurs the specified Object
+               /// is not of type <code>LdapAttribute</code>.
+               /// </returns>
+               public override bool Add(object attr)
+               {
+                       //We must enforce that attr is an LdapAttribute
+                       LdapAttribute attribute = (LdapAttribute) attr;
+                       System.String name = attribute.Name.ToUpper();
+                       if (this.map.ContainsKey(name))
+                               return false;
+                       else
+                       {
+                               SupportClass.PutElement(this.map, name, attribute);
+                               return true;
+                       }
+               }
+               
+               /// <summary> Removes the specified object from this set if it is present.
+               /// 
+               /// <p>If the specified object is of type <code>LdapAttribute</code>, the
+               /// specified attribute will be removed.  If the specified object is of type
+               /// <code>String</code>, the attribute with a name that matches the string will
+               /// be removed.</p>
+               /// 
+               /// </summary>
+               /// <param name="object">LdapAttribute to be removed or <code>String</code> naming
+               /// the attribute to be removed.
+               /// 
+               /// </param>
+               /// <returns> true if the object was removed.
+               /// 
+               /// @throws ClassCastException occurs the specified Object
+               /// is not of type <code>LdapAttribute</code> or of type <code>String</code>.
+               /// </returns>
+               public override bool Remove(object object_Renamed)
+               {
+                       System.String attributeName; //the name is the key to object in the HashMap
+                       if (object_Renamed is System.String)
+                       {
+                               attributeName = ((System.String) object_Renamed);
+                       }
+                       else
+                       {
+                               attributeName = ((LdapAttribute) object_Renamed).Name;
+                       }
+                       if ((System.Object) attributeName == null)
+                       {
+                               return false;
+                       }
+                       return (SupportClass.HashtableRemove(this.map, attributeName.ToUpper()) != null);
+               }
+               
+               /// <summary> Removes all of the elements from this set.</summary>
+               public override void Clear()
+               {
+                       this.map.Clear();
+               }
+               
+               /// <summary> Adds all <code>LdapAttribute</code> objects in the specified collection to
+               /// this collection.
+               /// 
+               /// </summary>
+               /// <param name="c"> Collection of <code>LdapAttribute</code> objects.
+               /// 
+               /// @throws ClassCastException occurs when an element in the
+               /// collection is not of type <code>LdapAttribute</code>.
+               /// 
+               /// </param>
+               /// <returns> true if this set changed as a result of the call.
+               /// </returns>
+               public override bool AddAll(System.Collections.ICollection c)
+               {
+                       bool setChanged = false;
+                       System.Collections.IEnumerator i = c.GetEnumerator();
+                       
+                       while (i.MoveNext())
+                       {
+                               // we must enforce that everything in c is an LdapAttribute
+                               // add will return true if the attribute was added
+                               if (this.Add(i.Current))
+                               {
+                                       setChanged = true;
+                               }
+                       }
+                       return setChanged;
+               }
+               
+               /// <summary> Returns a string representation of this LdapAttributeSet
+               /// 
+               /// </summary>
+               /// <returns> a string representation of this LdapAttributeSet
+               /// </returns>
+               public override System.String ToString()
+               {
+                       System.Text.StringBuilder retValue = new System.Text.StringBuilder("LdapAttributeSet: ");
+                       System.Collections.IEnumerator attrs = GetEnumerator();
+                       bool first = true;
+                       while (attrs.MoveNext())
+                       {
+                               if (!first)
+                               {
+                                       retValue.Append(" ");
+                               }
+                               first = false;
+                               LdapAttribute attr = (LdapAttribute) attrs.Current;
+                               retValue.Append(attr.ToString());
+                       }
+                       return retValue.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAuthHandler.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAuthHandler.cs
new file mode 100755 (executable)
index 0000000..ea5480d
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapAuthHandler.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Used to provide credentials for authentication when processing a
+       /// referral.
+       /// 
+       /// <p>A programmer desiring to supply authentication credentials
+       /// to the API when automatically following referrals MUST
+       /// implement this interface. If LdapAuthHandler or LdapBindHandler are not
+       /// implemented, automatically followed referrals will use anonymous
+       /// authentication. Referral URLs of any type other than Ldap (i.e. a
+       /// referral URL other than ldap://something) are not chased automatically
+       /// by the API on automatic following.</p>
+       /// 
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapBindHandler">
+       /// </seealso>
+       /// <seealso cref="LdapConstraints#setReferralFollowing(boolean)">
+       /// </seealso>
+       public interface LdapAuthHandler : LdapReferralHandler
+               {
+                       
+                       /// <summary> Returns an object which can provide credentials for authenticating to
+                       /// a server at the specified host and port.
+                       /// 
+                       /// </summary>
+                       /// <param name="host">   Contains a host name or the IP address (in dotted string
+                       /// format) of a host running an Ldap server.
+                       /// <br><br>
+                       /// </param>
+                       /// <param name="port">   Contains the TCP or UDP port number of the host.
+                       /// 
+                       /// </param>
+                       /// <returns> An object with authentication credentials to the specified
+                       /// host and port.
+                       /// </returns>
+                       LdapAuthProvider getAuthProvider(System.String host, int port);
+               }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAuthProvider.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapAuthProvider.cs
new file mode 100755 (executable)
index 0000000..2973b22
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapAuthProvider.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  An implementation of LdapAuthHandler must be able to provide an
+       /// LdapAuthProvider object at the time of a referral.  The class
+       /// encapsulates information that is used by the client for authentication
+       /// when following referrals automatically.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapAuthHandler">
+       /// </seealso>
+       /// <seealso cref="LdapBindHandler">
+       /// </seealso>
+       /// <seealso cref="LdapConstraints#setReferralFollowing(boolean)">
+       /// </seealso>
+       public class LdapAuthProvider
+       {
+               /// <summary> Returns the distinguished name to be used for authentication on
+               /// automatic referral following.
+               /// 
+               /// </summary>
+               /// <returns> The distinguished name from the object.
+               /// </returns>
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return dn;
+                       }
+                       
+               }
+               /// <summary> Returns the password to be used for authentication on automatic
+               /// referral following.
+               /// 
+               /// </summary>
+               /// <returns> The byte[] value (UTF-8) of the password from the object.
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               virtual public sbyte[] Password
+               {
+                       get
+                       {
+                               return password;
+                       }
+                       
+               }
+               
+               private System.String dn;
+               private sbyte[] password;
+               
+               /// <summary> Constructs information that is used by the client for authentication
+               /// when following referrals automatically.
+               /// 
+               /// </summary>
+               /// <param name="dn">          The distinguished name to use when authenticating to
+               /// a server.
+               /// <br><br>
+               /// </param>
+               /// <param name="password">    The password to use when authenticating to a server.
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public LdapAuthProvider(System.String dn, sbyte[] password)
+               {
+                       this.dn = dn;
+                       this.password = password;
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapBindHandler.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapBindHandler.cs
new file mode 100755 (executable)
index 0000000..e2c15bf
--- /dev/null
@@ -0,0 +1,90 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapBindHandler.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Used to do explicit bind processing on a referral.
+       /// 
+       /// <p>This interface allows a programmer to override the default
+       /// authentication and reauthentication behavior when automatically
+       /// following referrals and search references. It is used to control the
+       /// authentication mechanism used on automatic referral following.</p>
+       /// 
+       /// <p>A client can specify an instance of this class to be used
+       /// on a single operation (through the LdapConstraints object)
+       /// or for all operations (through the LdapContraints object
+       /// associated with the connection).
+       /// 
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapAuthHandler">
+       /// </seealso>
+       /// <seealso cref="LdapConstraints#setReferralFollowing(boolean)">
+       /// </seealso>
+       public interface LdapBindHandler : LdapReferralHandler
+               {
+                       
+                       /// <summary> Called by LdapConnection when a referral is received.
+                       /// 
+                       /// <p>This method has the responsibility to bind to one of the
+                       /// hosts in the list specified by the ldaprul parameter which corresponds
+                       /// exactly to the list of hosts returned in a single referral response.
+                       /// An implementation may access the host, port, credentials, and other
+                       /// information in the original LdapConnection object to decide on an
+                       /// appropriate authentication mechanism, and/or interact with a user or
+                       /// external module. The object implementing LdapBind creates a new
+                       /// LdapConnection object to perform its connect and bind calls.  It
+                       /// returns the new connection when both the connect and bind operations
+                       /// succeed on one host from the list.  The LdapConnection object referral
+                       /// following code uses the new LdapConnection object when it resends the
+                       /// search request, updated with the new search base and possible search
+                       /// filter. An LdapException is thrown on failure, as in the
+                       /// LdapConnection.bind method. </p>
+                       /// 
+                       /// </summary>
+                       /// <param name="ldapurl">The list of servers contained in a referral response.
+                       /// </param>
+                       /// <param name="conn">   An established connection to an Ldap server.
+                       /// 
+                       /// </param>
+                       /// <returns>       An established connection to one of the ldap servers
+                       /// in the referral list.
+                       /// 
+                       /// </returns>
+                       /// <exception cref="">  LdapReferralException An LdapreferralException is thrown
+                       /// with appropriate fields set to give the reason for the failure.
+                       /// </exception>
+                       LdapConnection Bind(System.String[] ldapurl, LdapConnection conn);
+               }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapBindRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapBindRequest.cs
new file mode 100755 (executable)
index 0000000..cee5fa4
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapBindRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents a simple bind request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso>
+   /*
+       *       BindRequest ::= [APPLICATION 0] SEQUENCE {
+       *               version                 INTEGER (1 .. 127),
+       *               name                    LdapDN,
+       *               authentication          AuthenticationChoice }
+       */
+       public class LdapBindRequest:LdapMessage
+       {
+               /// <summary> Retrieves the Authentication DN for a bind request.
+               /// 
+               /// </summary>
+               /// <returns> the Authentication DN for a bind request
+               /// </returns>
+               virtual public System.String AuthenticationDN
+               {
+                       get
+                       {
+                               return Asn1Object.RequestDN;
+                       }
+                       
+               }
+               /// <summary> Constructs a simple bind request.
+               /// 
+               /// </summary>
+               /// <param name="version"> The Ldap protocol version, use Ldap_V3.
+               /// Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// 
+               /// </param>
+               /// <param name="cont">Any controls that apply to the simple bind request,
+               /// or null if none.
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public LdapBindRequest(int version, System.String dn, sbyte[] passwd, LdapControl[] cont):base(LdapMessage.BIND_REQUEST, new RfcBindRequest(new Asn1Integer(version), new RfcLdapDN(dn), new RfcAuthenticationChoice(new Asn1Tagged(new Asn1Identifier(Asn1Identifier.CONTEXT, false, 0), new Asn1OctetString(passwd), false))), cont)
+               {
+                       return ;
+               }
+               
+               /// <summary> Return an Asn1 representation of this add request.
+               /// 
+               /// #return an Asn1 representation of this object.
+               /// </summary>
+               public override System.String ToString()
+               {
+                       return Asn1Object.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapCompareAttrNames.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapCompareAttrNames.cs
new file mode 100755 (executable)
index 0000000..f46a49f
--- /dev/null
@@ -0,0 +1,299 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapCompareAttrNames.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       
+       /// <summary>  Compares Ldap entries based on attribute name.
+       /// 
+       /// <p>An object of this class defines ordering when sorting LdapEntries,
+       /// usually from search results.  When using this Comparator, LdapEntry objects
+       /// are sorted by the attribute names(s) passed in on the
+       /// constructor, in ascending or descending order.  The object is typically
+       /// supplied to an implementation of the collection interfaces such as
+       /// java.util.TreeSet which performs sorting. </p>
+       /// 
+       /// <p>Comparison is performed via locale-sensitive Java String comparison,
+       /// which may not correspond to the Ldap ordering rules by which an Ldap server
+       /// would sort them.
+       /// 
+       /// </summary>
+       public class LdapCompareAttrNames : System.Collections.IComparer
+       {
+               private void  InitBlock()
+               {
+//                     location = Locale.getDefault();
+                       location=System.Globalization.CultureInfo.CurrentCulture;
+                       collator = System.Globalization.CultureInfo.CurrentCulture.CompareInfo;
+               }
+               /// <summary> Returns the locale to be used for sorting, if a locale has been
+               /// specified.
+               /// 
+               /// <p>If locale is null, a basic String.compareTo method is used for
+               /// collation.  If non-null, a locale-specific collation is used. </p>
+               /// 
+               /// </summary>
+               /// <returns> The locale if one has been specified
+               /// </returns>
+               /// <summary> Sets the locale to be used for sorting.
+               /// 
+               /// </summary>
+               /// <param name="locale">  The locale to be used for sorting.
+               /// </param>
+               virtual public System.Globalization.CultureInfo Locale
+               {
+                       get
+                       {
+                               //currently supports only English local.
+                               return location;
+                       }
+                       
+                       set
+                       {
+                               collator = value.CompareInfo;
+                               location = value;
+                       }
+                       
+               }
+               private System.String[] sortByNames; //names to to sort by.
+               private bool[] sortAscending; //true if sorting ascending
+               private System.Globalization.CultureInfo location;
+               private System.Globalization.CompareInfo collator;
+               
+               /// <summary> Constructs an object that sorts results by a single attribute, in
+               /// ascending order.
+               /// 
+               /// </summary>
+               /// <param name="attrName">      Name of an attribute by which to sort.
+               /// 
+               /// </param>
+               public LdapCompareAttrNames(System.String attrName)
+               {
+                       InitBlock();
+                       sortByNames = new System.String[1];
+                       sortByNames[0] = attrName;
+                       sortAscending = new bool[1];
+                       sortAscending[0] = true;
+               }
+               
+               /// <summary> Constructs an object that sorts results by a single attribute, in
+               /// either ascending or descending order.
+               /// 
+               /// </summary>
+               /// <param name="attrName">      Name of an attribute to sort by.
+               /// <br><br>
+               /// </param>
+               /// <param name="ascendingFlag"> True specifies ascending order; false specifies
+               /// descending order.
+               /// </param>
+               public LdapCompareAttrNames(System.String attrName, bool ascendingFlag)
+               {
+                       InitBlock();
+                       sortByNames = new System.String[1];
+                       sortByNames[0] = attrName;
+                       sortAscending = new bool[1];
+                       sortAscending[0] = ascendingFlag;
+               }
+               
+               
+               /// <summary> Constructs an object that sorts by one or more attributes, in the
+               /// order provided, in ascending order.
+               /// 
+               /// <p>Note: Novell eDirectory allows sorting by one attribute only. The
+               /// direcctory server must also be configured to index the specified
+               /// attribute.</p>
+               /// 
+               /// </summary>
+               /// <param name="attrNames">     Array of names of attributes to sort by.
+               /// 
+               /// </param>
+               public LdapCompareAttrNames(System.String[] attrNames)
+               {
+                       InitBlock();
+                       sortByNames = new System.String[attrNames.Length];
+                       sortAscending = new bool[attrNames.Length];
+                       for (int i = 0; i < attrNames.Length; i++)
+                       {
+                               sortByNames[i] = attrNames[i];
+                               sortAscending[i] = true;
+                       }
+               }
+               
+               /// <summary> Constructs an object that sorts by one or more attributes, in the
+               /// order provided, in either ascending or descending order for each
+               /// attribute.
+               /// 
+               /// <p>Note: Novell eDirectory supports only ascending sort order (A,B,C ...)
+               /// and allows sorting only by one attribute. The directory server must be
+               /// configured to index this attribute.</p>
+               /// 
+               /// </summary>
+               /// <param name="attrNames">     Array of names of attributes to sort by.
+               /// <br><br>
+               /// </param>
+               /// <param name="ascendingFlags"> Array of flags, one for each attrName, where
+               /// true specifies ascending order and false specifies
+               /// descending order. An LdapException is thrown if
+               /// the length of ascendingFlags is not greater than
+               /// or equal to the length of attrNames.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               public LdapCompareAttrNames(System.String[] attrNames, bool[] ascendingFlags)
+               {
+                       InitBlock();
+                       if (attrNames.Length != ascendingFlags.Length)
+                       {
+                               throw new LdapException(ExceptionMessages.UNEQUAL_LENGTHS, LdapException.INAPPROPRIATE_MATCHING, (System.String) null);
+                               //"Length of attribute Name array does not equal length of Flags array"
+                       }
+                       sortByNames = new System.String[attrNames.Length];
+                       sortAscending = new bool[ascendingFlags.Length];
+                       for (int i = 0; i < attrNames.Length; i++)
+                       {
+                               sortByNames[i] = attrNames[i];
+                               sortAscending[i] = ascendingFlags[i];
+                       }
+               }
+               
+               /// <summary> Compares the the attributes of the first LdapEntry to the second.
+               /// <p>Only the values of the attributes named at the construction of this
+               /// object will be compared.  Multi-valued attributes compare on the first
+               /// value only.  </p>
+               /// 
+               /// </summary>
+               /// <param name="object1">        Target entry for comparison.
+               /// 
+               /// </param>
+               /// <param name="object2">        Entry to be compared to.
+               /// 
+               /// </param>
+               /// <returns>     Negative value if the first entry is less than the second and
+               /// positive if the first is greater than the second.  Zero is returned if all
+               /// attributes to be compared are the same.
+               /// </returns>
+               public virtual int Compare(System.Object object1, System.Object object2)
+               {
+                       LdapEntry entry1 = (LdapEntry) object1;
+                       LdapEntry entry2 = (LdapEntry) object2;
+                       LdapAttribute one, two;
+                       System.String[] first; //multivalued attributes are ignored.
+                       System.String[] second; //we just use the first element
+                       int compare, i = 0;
+                       if (collator == null)
+                       {
+                               //using default locale
+                               collator = System.Globalization.CultureInfo.CurrentCulture.CompareInfo;
+                       }
+                       
+                       do 
+                       {
+                               //while first and second are equal
+                               one = entry1.getAttribute(sortByNames[i]);
+                               two = entry2.getAttribute(sortByNames[i]);
+                               if ((one != null) && (two != null))
+                               {
+                                       first = one.StringValueArray;
+                                       second = two.StringValueArray;
+                                       compare = collator.Compare(first[0], second[0]);
+                               }
+                               //We could also use the other multivalued attributes to break ties.
+                               //one of the entries was null
+                               else
+                               {
+                                       if (one != null)
+                                               compare = - 1;
+                                       //one is greater than two
+                                       else if (two != null)
+                                               compare = 1;
+                                       //one is lesser than two
+                                       else
+                                               compare = 0; //tie - break it with the next attribute name
+                               }
+                               
+                               i++;
+                       }
+                       while ((compare == 0) && (i < sortByNames.Length));
+                       
+                       if (sortAscending[i - 1])
+                       {
+                               // return the normal ascending comparison.
+                               return compare;
+                       }
+                       else
+                       {
+                               // negate the comparison for a descending comparison.
+                               return - compare;
+                       }
+               }
+               
+               /// <summary> Determines if this comparator is equal to the comparator passed in.
+               /// 
+               /// <p> This will return true if the comparator is an instance of
+               /// LdapCompareAttrNames and compares the same attributes names in the same
+               /// order.</p>
+               /// 
+               /// </summary>
+               /// <returns> true the comparators are equal
+               /// </returns>
+               public override bool Equals(System.Object comparator)
+               {
+                       if (!(comparator is LdapCompareAttrNames))
+                       {
+                               return false;
+                       }
+                       LdapCompareAttrNames comp = (LdapCompareAttrNames) comparator;
+                       
+                       // Test to see if the attribute to compare are the same length
+                       if ((comp.sortByNames.Length != this.sortByNames.Length) || (comp.sortAscending.Length != this.sortAscending.Length))
+                       {
+                               return false;
+                       }
+                       
+                       // Test to see if the attribute names and sorting orders are the same.
+                       for (int i = 0; i < this.sortByNames.Length; i++)
+                       {
+                               if (comp.sortAscending[i] != this.sortAscending[i])
+                                       return false;
+                               if (!comp.sortByNames[i].ToUpper().Equals(this.sortByNames[i].ToUpper()))
+                                       return false;
+                       }
+                       return true;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapCompareRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapCompareRequest.cs
new file mode 100755 (executable)
index 0000000..d7b7d52
--- /dev/null
@@ -0,0 +1,115 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapCompareRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap Compare Request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso>
+   /*
+       *       CompareRequest ::= [APPLICATION 14] SEQUENCE {
+       *               entry           LdapDN,
+       *               ava             AttributeValueAssertion }
+       */
+       public class LdapCompareRequest:LdapMessage
+       {
+               /// <summary> Returns the LdapAttribute associated with this request.
+               /// 
+               /// </summary>
+               /// <returns> the LdapAttribute
+               /// </returns>
+               virtual public System.String AttributeDescription
+               {
+                       get
+                       {
+                               RfcCompareRequest req = (RfcCompareRequest) Asn1Object.getRequest();
+                               return req.AttributeValueAssertion.AttributeDescription;
+                       }
+                       
+               }
+               /// <summary> Returns the LdapAttribute associated with this request.
+               /// 
+               /// </summary>
+               /// <returns> the LdapAttribute
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               virtual public sbyte[] AssertionValue
+               {
+                       get
+                       {
+                               RfcCompareRequest req = (RfcCompareRequest) Asn1Object.getRequest();
+                               return req.AttributeValueAssertion.AssertionValue;
+                       }
+                       
+               }
+               /// <summary> Returns of the dn of the entry to compare in the directory
+               /// 
+               /// </summary>
+               /// <returns> the dn of the entry to compare
+               /// </returns>
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return Asn1Object.RequestDN;
+                       }
+                       
+               }
+               /// <summary> Constructs an LdapCompareRequest Object.
+               /// <br><br>
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry containing an
+               /// attribute to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="name">   The name of the attribute to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="value">   The value of the attribute to compare.
+               /// 
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">Any controls that apply to the compare request,
+               /// or null if none.
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public LdapCompareRequest(System.String dn, System.String name, sbyte[] value_Renamed, LdapControl[] cont):base(LdapMessage.COMPARE_REQUEST, new RfcCompareRequest(new RfcLdapDN(dn), new RfcAttributeValueAssertion(new RfcAttributeDescription(name), new RfcAssertionValue(value_Renamed))), cont)
+               {
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConnection.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConnection.cs
new file mode 100755 (executable)
index 0000000..b296d1e
--- /dev/null
@@ -0,0 +1,3625 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapConnection.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> The central class that encapsulates the connection
+       /// to a directory server through the Ldap protocol.
+       /// LdapConnection objects are used to perform common Ldap
+       /// operations such as search, modify and add.
+       /// 
+       /// <p>In addition, LdapConnection objects allow you to bind to an
+       /// Ldap server, set connection and search constraints, and perform
+       /// several other tasks.
+       /// 
+       /// <p>An LdapConnection object is not connected on
+       /// construction and can only be connected to one server at one
+       /// port. Multiple threads may share this single connection, typically
+       /// by cloning the connection object, one for each thread. An
+       /// application may have more than one LdapConnection object, connected
+       /// to the same or different directory servers.</p>
+       /// 
+       /// 
+       /// </summary>
+       public class LdapConnection : System.ICloneable
+       {
+               private void  InitBlock()
+               {
+                       defSearchCons = new LdapSearchConstraints();
+                       responseCtlSemaphore = new System.Object();
+               }
+               /// <summary> Returns the protocol version uses to authenticate.
+               /// 
+               /// <p> 0 is returned if no authentication has been performed.</p>
+               /// 
+               /// </summary>
+               /// <returns> The protol version used for authentication or 0
+               /// not authenticated.
+               /// 
+               /// </returns>
+               /// <seealso cref="int, String, String)">
+               /// </seealso>
+               virtual public int ProtocolVersion
+               {
+                       get
+                       {
+                               BindProperties prop = conn.BindProperties;
+                               if (prop == null)
+                               {
+                                       return Ldap_V3;
+                               }
+                               return prop.ProtocolVersion;
+                       }
+                       
+               }
+               /// <summary> Returns the distinguished name (DN) used for as the bind name during
+               /// the last successful bind operation.  <code>null</code> is returned
+               /// if no authentication has been performed or if the bind resulted in
+               /// an aonymous connection.
+               /// 
+               /// </summary>
+               /// <returns> The distinguished name if authenticated; otherwise, null.
+               /// 
+               /// </returns>
+               /// <seealso cref="String, String)">
+               /// </seealso>
+               /// <seealso cref="#isBound()">
+               /// </seealso>
+               virtual public System.String AuthenticationDN
+               {
+                       get
+                       {
+                               BindProperties prop = conn.BindProperties;
+                               if (prop == null)
+                               {
+                                       return null;
+                               }
+                               if (prop.Anonymous)
+                               {
+                                       return null;
+                               }
+                               return prop.AuthenticationDN;
+                       }
+                       
+               }
+               /// <summary> Returns the method used to authenticate the connection. The return
+               /// value is one of the following:
+               /// 
+               /// <ul>
+               /// <li>"none" indicates the connection is not authenticated.</li>
+               /// 
+               /// 
+               /// <li>"simple" indicates simple authentication was used or that a null
+               /// or empty authentication DN was specified.</li>
+               /// 
+               /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
+               /// </ul>
+               /// 
+               /// </summary>
+               /// <returns> The method used to authenticate the connection.
+               /// </returns>
+               virtual public System.String AuthenticationMethod
+               {
+                       get
+                       {
+                               BindProperties prop = conn.BindProperties;
+                               if (prop == null)
+                               {
+                                       return "simple";
+                               }
+                               return conn.BindProperties.AuthenticationMethod;
+                       }
+                       
+               }
+               /// <summary> Returns the properties if any specified on binding with a
+               /// SASL mechanism.
+               /// 
+               /// <p> Null is returned if no authentication has been performed
+               /// or no authentication Map is present.</p>
+               /// 
+               /// </summary>
+               /// <returns> The bind properties Map Object used for SASL bind or null if
+               /// the connection is not present or not authenticated.
+               /// 
+               /// </returns>
+               /// <seealso cref="String, String, String[], Map, Object )">
+               /// </seealso>
+               virtual public System.Collections.IDictionary SaslBindProperties
+               {
+                       get
+                       {
+                               BindProperties prop = conn.BindProperties;
+                               if (prop == null)
+                               {
+                                       return null;
+                               }
+                               return conn.BindProperties.SaslBindProperties;
+                       }
+                       
+               }
+               /// <summary> Returns the call back handler if any specified on binding with a
+               /// SASL mechanism.
+               /// 
+               /// <p> Null is returned if no authentication has been performed
+               /// or no authentication call back handler is present.</p>
+               /// 
+               /// </summary>
+               /// <returns> The call back handler used for SASL bind or null if the
+               /// object is not present or not authenticated.
+               /// 
+               /// </returns>
+               /// <seealso cref="String, String, String[], Map, Object )">
+               /// </seealso>
+               virtual public System.Object SaslBindCallbackHandler
+               {
+                       get
+                       {
+                               BindProperties prop = conn.BindProperties;
+                               if (prop == null)
+                               {
+                                       return null;
+                               }
+                               return conn.BindProperties.SaslCallbackHandler;
+                       }
+                       
+               }
+               /// <summary> Returns a copy of the set of constraints associated with this
+               /// connection. These constraints apply to all operations performed
+               /// through this connection (unless a different set of constraints is
+               /// specified when calling an operation method).
+               /// 
+               /// </summary>
+               /// <returns> The set of default contraints that apply to this connection.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setConstraints(LdapConstraints)">
+               /// </seealso>
+               /// <summary> Sets the constraints that apply to all operations performed through
+               /// this connection (unless a different set of constraints is specified
+               /// when calling an operation method).  An LdapSearchConstraints object
+               /// which is passed to this method sets all constraints, while an
+               /// LdapConstraints object passed to this method sets only base constraints.
+               /// 
+               /// </summary>
+               /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
+               /// containing the contstraint values to set.
+               /// 
+               /// </param>
+               /// <seealso cref="#getConstraints()">
+               /// </seealso>
+               /// <seealso cref="#getSearchConstraints()">
+               /// </seealso>
+               virtual public LdapConstraints Constraints
+               {
+                       get
+                       {
+                               return (LdapConstraints) (this.defSearchCons).Clone();
+                       }
+                       
+                       set
+                       {
+                               // Set all constraints, replace the object with a new one
+                               if (value is LdapSearchConstraints)
+                               {
+                                       defSearchCons = (LdapSearchConstraints) value.Clone();
+                                       return ;
+                               }
+                               
+                               // We set the constraints this way, so a thread doesn't get an
+                               // conconsistant view of the referrals.
+                               LdapSearchConstraints newCons = (LdapSearchConstraints) defSearchCons.Clone();
+                               newCons.HopLimit = value.HopLimit;
+                               newCons.TimeLimit = value.TimeLimit;
+                               newCons.setReferralHandler(value.getReferralHandler());
+                               newCons.ReferralFollowing = value.ReferralFollowing;
+                               LdapControl[] lsc = value.getControls();
+                               if (lsc != null)
+                               {
+                                       newCons.setControls(lsc);
+                               }
+                               System.Collections.Hashtable lp = newCons.Properties;
+                               if (lp != null)
+                               {
+                                       newCons.Properties = lp;
+                               }
+                               defSearchCons = newCons;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Returns the host name of the Ldap server to which the object is or
+               /// was last connected, in the format originally specified.
+               /// 
+               /// </summary>
+               /// <returns> The host name of the Ldap server to which the object last
+               /// connected or null if the object has never connected.
+               /// 
+               /// </returns>
+               /// <seealso cref="String, int)">
+               /// </seealso>
+               virtual public System.String Host
+               {
+                       get
+                       {
+                               return conn.Host;
+                       }
+                       
+               }
+               /// <summary> Returns the port number of the Ldap server to which the object is or
+               /// was last connected.
+               /// 
+               /// </summary>
+               /// <returns> The port number of the Ldap server to which the object last
+               /// connected or -1 if the object has never connected.
+               /// 
+               /// </returns>
+               /// <seealso cref="String, int)">
+               /// </seealso>
+               virtual public int Port
+               {
+                       get
+                       {
+                               return conn.Port;
+                       }
+                       
+               }
+               /// <summary> Returns a copy of the set of search constraints associated with this
+               /// connection. These constraints apply to search operations performed
+               /// through this connection (unless a different set of
+               /// constraints is specified when calling the search operation method).
+               /// 
+               /// </summary>
+               /// <returns> The set of default search contraints that apply to
+               /// this connection.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setConstraints">
+               /// </seealso>
+               /// <seealso cref="String, int, String, String[], boolean, LdapSearchConstraints)">
+               /// </seealso>
+               virtual public LdapSearchConstraints SearchConstraints
+               {
+                       get
+                       {
+                               return (LdapSearchConstraints) this.defSearchCons.Clone();
+                       }
+                       
+               }
+               /// <summary> Indicates whether the object has authenticated to the connected Ldap
+               /// server.
+               /// 
+               /// </summary>
+               /// <returns> True if the object has authenticated; false if it has not
+               /// authenticated.
+               /// 
+               /// </returns>
+               /// <seealso cref="String, String)">
+               /// </seealso>
+               virtual public bool Bound
+               {
+                       get
+                       {
+                               return conn.Bound;
+                       }
+                       
+               }
+               /// <summary> Indicates whether the connection represented by this object is open
+               /// at this time.
+               /// 
+               /// </summary>
+               /// <returns>  True if connection is open; false if the connection is closed.
+               /// </returns>
+               virtual public bool Connected
+               {
+                       get
+                       {
+                               return conn.Connected;
+                       }
+                       
+               }
+               /// <summary>  Returns the Server Controls associated with the most recent response
+               /// to a synchronous request on this connection object, or null
+               /// if the latest response contained no Server Controls. The method
+               /// always returns null for asynchronous requests. For asynchronous
+               /// requests, the response controls are available in LdapMessage.
+               /// 
+               /// </summary>
+               /// <returns> The server controls associated with the most recent response
+               /// to a synchronous request or null if the response contains no server
+               /// controls.
+               /// 
+               /// </returns>
+               /// <seealso cref="LdapMessage#getControls()">
+               /// </seealso>
+               virtual public LdapControl[] ResponseControls
+               {
+                       get
+                       {
+                               if (responseCtls == null)
+                               {
+                                       return null;
+                               }
+                               
+                               
+                               // We have to clone the control just in case
+                               // we have two client threads that end up retreiving the
+                               // same control.
+                               LdapControl[] clonedControl = new LdapControl[responseCtls.Length];
+                               
+                               // Also note we synchronize access to the local response
+                               // control object just in case another message containing controls
+                               // comes in from the server while we are busy duplicating
+                               // this one.
+                               lock (responseCtlSemaphore)
+                               {
+                                       for (int i = 0; i < responseCtls.Length; i++)
+                                       {
+                                               clonedControl[i] = (LdapControl) (responseCtls[i]).Clone();
+                                       }
+                               }
+                               
+                               // Return the cloned copy.  Note we have still left the
+                               // control in the local responseCtls variable just in case
+                               // somebody requests it again.
+                               return clonedControl;
+                       }
+                       
+               }
+               /// <summary> Return the Connection object associated with this LdapConnection
+               /// 
+               /// </summary>
+               /// <returns> the Connection object
+               /// </returns>
+               virtual internal Connection Connection
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return conn;
+                       }
+                       
+               }
+               /// <summary> Return the Connection object name associated with this LdapConnection
+               /// 
+               /// </summary>
+               /// <returns> the Connection object name
+               /// </returns>
+               virtual internal System.String ConnectionName
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return name;
+                       }
+                       
+               }
+               private LdapSearchConstraints defSearchCons;
+               private LdapControl[] responseCtls = null;
+               
+               // Synchronization Object used to synchronize access to responseCtls
+               private System.Object responseCtlSemaphore;
+               
+               private Connection conn = null;
+               
+               private static System.Object nameLock; // protect agentNum
+               private static int lConnNum = 0; // Debug, LdapConnection number
+               private System.String name; // String name for debug
+               
+               /// <summary> Used with search to specify that the scope of entrys to search is to
+               /// search only the base obect.
+               /// 
+               /// <p>SCOPE_BASE = 0</p>
+               /// </summary>
+               public const int SCOPE_BASE = 0;
+               
+               /// <summary> Used with search to specify that the scope of entrys to search is to
+               /// search only the immediate subordinates of the base obect.
+               /// 
+               /// <p>SCOPE_ONE = 1</p>
+               /// </summary>
+               public const int SCOPE_ONE = 1;
+               
+               /// <summary> Used with search to specify that the scope of entrys to search is to
+               /// search the base object and all entries within its subtree.
+               /// 
+               /// <p>SCOPE_ONE = 2</p>
+               /// </summary>
+               public const int SCOPE_SUB = 2;
+               
+               /// <summary> Used with search instead of an attribute list to indicate that no
+               /// attributes are to be returned.
+               /// 
+               /// <p>NO_ATTRS = "1.1"</p>
+               /// </summary>
+               public const System.String NO_ATTRS = "1.1";
+               
+               /// <summary> Used with search instead of an attribute list to indicate that all
+               /// attributes are to be returned.
+               /// 
+               /// <p>ALL_USER_ATTRS = "*"</p>
+               /// </summary>
+               public const System.String ALL_USER_ATTRS = "*";
+               
+               /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
+               /// 
+               /// <p>Specifies Ldap version V3 of the protocol, and is specified
+               /// when performing bind operations.
+               /// <p>You can use this identifier in the version parameter
+               /// of the bind method to specify an Ldapv3 bind.
+               /// Ldap_V3 is the default protocol version</p>
+               /// 
+               /// <p>Ldap_V3 = 3</p>
+               /// 
+               /// </summary>
+               /// <seealso cref="String, byte[])">
+               /// </seealso>
+               /// <seealso cref="String, byte[], LdapConstraints)">
+               /// </seealso>
+               /// <seealso cref="String, byte[], LdapResponseQueue)">
+               /// </seealso>
+               /// <seealso cref="String, byte[], LdapResponseQueue, LdapConstraints)">
+               /// </seealso>
+               public const int Ldap_V3 = 3;
+               
+               /// <summary> The default port number for Ldap servers.
+               /// 
+               /// <p>You can use this identifier to specify the port when establishing
+               /// a clear text connection to a server.  This the default port.</p>
+               /// 
+               /// <p>DEFAULT_PORT = 389</p>
+               /// 
+               /// </summary>
+               /// <seealso cref="int)">
+               /// </seealso>
+               public const int DEFAULT_PORT = 389;
+               
+               
+               /// <summary> The default SSL port number for Ldap servers.
+               /// 
+               /// <p>DEFAULT_SSL_PORT = 636</p>
+               /// 
+               /// <p>You can use this identifier to specify the port when establishing
+               /// a an SSL connection to a server.</p>.
+               /// </summary>
+               public const int DEFAULT_SSL_PORT = 636;
+               
+               /// <summary> A string that can be passed in to the getProperty method.
+               /// 
+               /// <p>Ldap_PROPERTY_SDK = "version.sdk"</p>
+               /// 
+               /// <p>You can use this string to request the version of the SDK</p>.
+               /// </summary>
+               public const System.String Ldap_PROPERTY_SDK = "version.sdk";
+               
+               /// <summary> A string that can be passed in to the getProperty method.
+               /// 
+               /// <p>Ldap_PROPERTY_PROTOCOL = "version.protocol"</p>
+               /// 
+               /// <p>You can use this string to request the version of the
+               /// Ldap protocol</p>.
+               /// </summary>
+               public const System.String Ldap_PROPERTY_PROTOCOL = "version.protocol";
+               
+               /// <summary> A string that can be passed in to the getProperty method.
+               /// 
+               /// <p>Ldap_PROPERTY_SECURITY = "version.security"</p>
+               /// 
+               /// <p>You can use this string to request the type of security
+               /// being used</p>.
+               /// </summary>
+               public const System.String Ldap_PROPERTY_SECURITY = "version.security";
+               
+               /// <summary> A string that corresponds to the server shutdown notification OID.
+               /// This notification may be used by the server to advise the client that
+               /// the server is about to close the connection due to an error
+               /// condition.
+               /// 
+               /// <p>SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
+               /// </summary>
+               public const System.String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
+               
+               /// <summary> The OID string that identifies a StartTLS request and response.</summary>
+               private const System.String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
+               
+               /*
+               * Constructors
+               */
+               
+               
+               /// <summary> Constructs a new LdapConnection object, which will use the supplied
+               /// class factory to construct a socket connection during
+               /// LdapConnection.connect method.
+               /// 
+               /// </summary>
+               /// <param name="factory">    An object capable of producing a Socket.
+               /// 
+               /// </param>
+               /// <seealso cref="int)">
+               /// </seealso>
+               /// <seealso cref="#getSocketFactory()">
+               /// </seealso>
+               /// <seealso cref="LdapSocketFactory)">
+               /// </seealso>
+               public LdapConnection()
+               {
+                       InitBlock();
+                       // Get a unique connection name for debug
+                       conn = new Connection();
+                       return ;
+               }
+               
+               /*
+               * The following are methods that affect the operation of
+               * LdapConnection, but are not Ldap requests.
+               */
+               
+               /// <summary> Returns a copy of the object with a private context, but sharing the
+               /// network connection if there is one.
+               /// 
+               /// <p>The network connection remains open until all clones have
+               /// disconnected or gone out of scope. Any connection opened after
+               /// cloning is private to the object making the connection.</p>
+               /// 
+               /// <p>The clone can issue requests and freely modify options and search
+               /// constraints, and , without affecting the source object or other clones.
+               /// If the clone disconnects or reconnects, it is completely dissociated
+               /// from the source object and other clones. Reauthenticating in a clone,
+               /// however, is a global operation which will affect the source object
+               /// and all associated clones, because it applies to the single shared
+               /// physical connection. Any request by an associated object after one
+               /// has reauthenticated will carry the new identity.</p>
+               /// 
+               /// </summary>
+               /// <returns> A of the object.
+               /// </returns>
+               public System.Object Clone()
+               {
+                       LdapConnection newClone;
+                       System.Object newObj;
+                       try
+                       {
+                               newObj = base.MemberwiseClone();
+                               newClone = (LdapConnection) newObj;
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+                       newClone.conn = conn; // same underlying connection
+                       
+                       //now just duplicate the defSearchCons and responseCtls
+                       if (defSearchCons != null)
+                       {
+                               newClone.defSearchCons = (LdapSearchConstraints) defSearchCons.Clone();
+                       }
+                       else
+                       {
+                               newClone.defSearchCons = null;
+                       }
+                       if (responseCtls != null)
+                       {
+                               newClone.responseCtls = new LdapControl[responseCtls.Length];
+                               for (int i = 0; i < responseCtls.Length; i++)
+                               {
+                                       newClone.responseCtls[i] = (LdapControl) responseCtls[i].Clone();
+                               }
+                       }
+                       else
+                       {
+                               newClone.responseCtls = null;
+                       }
+                       conn.incrCloneCount(); // Increment the count of clones
+                       return newObj;
+               }
+               
+               /// <summary> Closes the connection, if open, and releases any other resources held
+               /// by the object.
+               /// 
+               /// </summary>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <seealso cref="#disconnect">
+               /// </seealso>
+               ~LdapConnection()
+               {
+                       // Disconnect did not come from user API call
+                       Disconnect(defSearchCons, false);
+                       return ;
+               }
+               
+               /// <summary> Returns a property of a connection object.
+               /// 
+               /// </summary>
+               /// <param name="name">  Name of the property to be returned.
+               /// 
+               /// <p>The following read-only properties are available
+               /// for any given connection:</p>
+               /// <ul>
+               /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
+               /// as a Float data type.</li>
+               /// 
+               /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
+               /// the Ldap protocol, as a Float data type.</li>
+               /// 
+               /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
+               /// types of authentication supported, as a
+               /// string.
+               /// </ul>
+               /// 
+               /// <p>A deep copy of the property is provided where applicable; a
+               /// client does not need to clone the object received.</p>
+               /// 
+               /// </param>
+               /// <returns> The object associated with the requested property,
+               /// or null if the property is not defined.
+               /// 
+               /// </returns>
+               /// <seealso cref="LdapConstraints#getProperty(String)">
+               /// </seealso>
+               /// <seealso cref="Object)">
+               /// </seealso>
+               public virtual System.Object getProperty(System.String name)
+               {
+                       if (name.ToUpper().Equals(Ldap_PROPERTY_SDK.ToUpper()))
+                               return Connection.sdk;
+                       else if (name.ToUpper().Equals(Ldap_PROPERTY_PROTOCOL.ToUpper()))
+                               return Connection.protocol;
+                       else if (name.ToUpper().Equals(Ldap_PROPERTY_SECURITY.ToUpper()))
+                               return Connection.security;
+                       else
+                       {
+                               return null;
+                       }
+               }
+               
+               /// <summary> Registers an object to be notified on arrival of an unsolicited
+               /// message from a server.
+               /// 
+               /// <p>An unsolicited message has the ID 0. A new thread is created and
+               /// the method "messageReceived" in each registered object is called in
+               /// turn.</p>
+               /// 
+               /// </summary>
+               /// <param name="listener"> An object to be notified on arrival of an
+               /// unsolicited message from a server.  This object must
+               /// implement the LdapUnsolicitedNotificationListener interface.
+               /// 
+               /// </param>
+               public virtual void  AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
+               {
+                       if (listener != null)
+                               conn.AddUnsolicitedNotificationListener(listener);
+               }
+               
+               
+               
+               /// <summary> Deregisters an object so that it will no longer be notified on
+               /// arrival of an unsolicited message from a server. If the object is
+               /// null or was not previously registered for unsolicited notifications,
+               /// the method does nothing.
+               /// 
+               /// 
+               /// </summary>
+               /// <param name="listener"> An object to no longer be notified on arrival of
+               /// an unsolicited message from a server.
+               /// 
+               /// </param>
+               public virtual void  RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
+               {
+                       
+                       if (listener != null)
+                               conn.RemoveUnsolicitedNotificationListener(listener);
+               }
+               
+               /// <summary> Starts Transport Layer Security (TLS) protocol on this connection
+               /// to enable session privacy.
+               /// 
+               /// <p>This affects the LdapConnection object and all cloned objects. A
+               /// socket factory that implements LdapTLSSocketFactory must be set on the
+               /// connection.</p>
+               /// 
+               /// </summary>
+               /// <exception cref=""> LdapException Thrown if TLS cannot be started.  If a
+               /// SocketFactory has been specified that does not implement
+               /// LdapTLSSocketFactory an LdapException is thrown.
+               /// 
+               /// </exception>
+               /// <seealso cref="#isTLS">
+               /// </seealso>
+               /// <seealso cref="#stopTLS">
+               /// </seealso>
+               /// <seealso cref="#setSocketFactory">
+               /// </seealso>
+               //*************************************************************************
+               // Below are all of the Ldap protocol operation methods
+               //*************************************************************************
+               
+               //*************************************************************************
+               // abandon methods
+               //*************************************************************************
+               
+               /// <summary> 
+               /// 
+               /// Notifies the server not to send additional results associated with
+               /// this LdapSearchResults object, and discards any results already
+               /// received.
+               /// 
+               /// </summary>
+               /// <param name="results">  An object returned from a search.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Abandon(LdapSearchResults results)
+               {
+                       Abandon(results, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// 
+               /// Notifies the server not to send additional results associated with
+               /// this LdapSearchResults object, and discards any results already
+               /// received.
+               /// 
+               /// </summary>
+               /// <param name="results">  An object returned from a search.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">    The contraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Abandon(LdapSearchResults results, LdapConstraints cons)
+               {
+                       results.Abandon();
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Abandons an asynchronous operation.
+               /// 
+               /// </summary>
+               /// <param name="id">     The ID of the asynchronous operation to abandon. The ID
+               /// can be obtained from the response queue for the
+               /// operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Abandon(int id)
+               {
+                       Abandon(id, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary>  Abandons an asynchronous operation, using the specified
+               /// constraints.
+               /// 
+               /// </summary>
+               /// <param name="id">The ID of the asynchronous operation to abandon.
+               /// The ID can be obtained from the search
+               /// queue for the operation.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">The contraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Abandon(int id, LdapConstraints cons)
+               {
+                       // We need to inform the Message Agent which owns this messageID to
+                       // remove it from the queue.
+                       try
+                       {
+                               MessageAgent agent = conn.getMessageAgent(id);
+                               agent.Abandon(id, cons);
+                               return ;
+                       }
+                       catch (System.FieldAccessException ex)
+                       {
+                               return ; // Ignore error
+                       }
+               }
+               
+               /// <summary> Abandons all outstanding operations managed by the queue.
+               /// 
+               /// <p>All operations in progress, which are managed by the specified queue,
+               /// are abandoned.</p>
+               /// 
+               /// </summary>
+               /// <param name="queue">    The queue returned from an asynchronous request.
+               /// All outstanding operations managed by the queue
+               /// are abandoned, and the queue is emptied.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Abandon(LdapMessageQueue queue)
+               {
+                       Abandon(queue, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> Abandons all outstanding operations managed by the queue.
+               /// 
+               /// <p>All operations in progress, which are managed by the specified
+               /// queue, are abandoned.</p>
+               /// 
+               /// </summary>
+               /// <param name="queue">    The queue returned from an asynchronous request.
+               /// All outstanding operations managed by the queue
+               /// are abandoned, and the queue is emptied.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">    The contraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Abandon(LdapMessageQueue queue, LdapConstraints cons)
+               {
+                       if (queue != null)
+                       {
+                               MessageAgent agent;
+                               if (queue is LdapSearchQueue)
+                               {
+                                       agent = queue.MessageAgent;
+                               }
+                               else
+                               {
+                                       agent = queue.MessageAgent;
+                               }
+                               int[] msgIds = agent.MessageIDs;
+                               for (int i = 0; i < msgIds.Length; i++)
+                               {
+                                       agent.Abandon(msgIds[i], cons);
+                               }
+                       }
+                       return ;
+               }
+               
+               //*************************************************************************
+               // add methods
+               //*************************************************************************
+               
+               /// <summary> Synchronously adds an entry to the directory.
+               /// 
+               /// </summary>
+               /// <param name="entry">   LdapEntry object specifying the distinguished
+               /// name and attributes of the new entry.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Add(LdapEntry entry)
+               {
+                       Add(entry, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Synchronously adds an entry to the directory, using the specified
+               /// constraints.
+               /// 
+               /// </summary>
+               /// <param name="entry">  LdapEntry object specifying the distinguished
+               /// name and attributes of the new entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               
+               public virtual void  Add(LdapEntry entry, LdapConstraints cons)
+               {
+                       LdapResponseQueue queue = Add(entry, null, cons);
+                       
+                       // Get a handle to the add response
+                       LdapResponse addResponse = (LdapResponse) (queue.getResponse());
+                       
+                       // Set local copy of responseControls synchronously if there were any
+                       lock (responseCtlSemaphore)
+                       {
+                               responseCtls = addResponse.Controls;
+                       }
+                       chkResultCode(queue, cons, addResponse);
+                       return ;
+               }
+               
+               /// <summary> Asynchronously adds an entry to the directory.
+               /// 
+               /// </summary>
+               /// <param name="entry">  LdapEntry object specifying the distinguished
+               /// name and attributes of the new entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">  Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue)
+               {
+                       return Add(entry, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously adds an entry to the directory, using the specified
+               /// constraints.
+               /// 
+               /// </summary>
+               /// <param name="entry">  LdapEntry object specifying the distinguished
+               /// name and attributes of the new entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue"> Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">  Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       // error check the parameters
+                       if (entry == null)
+                       {
+                               throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
+                       }
+                       if ((System.Object) entry.DN == null)
+                       {
+                               throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
+                       }
+                       
+                       LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
+                       
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, null);
+               }
+               
+               //*************************************************************************
+               // bind methods
+               //*************************************************************************
+               
+               /// <summary> Synchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) as an Ldapv3 bind, using the specified name and
+               /// password.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// <br><br>
+               /// Note: the application should use care in the use
+               /// of String password objects.  These are long lived
+               /// objects, and may expose a security risk, especially
+               /// in objects that are serialized.  The LdapConnection
+               /// keeps no long lived instances of these objects.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <deprecated> replaced by {@link #bind(int, String, byte[])}
+               /// </deprecated>
+               public virtual void  Bind(System.String dn, System.String passwd)
+               {
+                       Bind(Ldap_V3, dn, passwd, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> Synchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) using the specified name, password,
+               /// and Ldap version.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="version"> The Ldap protocol version, use Ldap_V3.
+               /// Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// <br><br>
+               /// Note: the application should use care in the use
+               /// of String password objects.  These are long lived
+               /// objects, and may expose a security risk, especially
+               /// in objects that are serialized.  The LdapConnection
+               /// keeps no long lived instances of these objects.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <deprecated> replaced by {@link #bind(int, String, byte[])}
+               /// </deprecated>
+               public virtual void  Bind(int version, System.String dn, System.String passwd)
+               {
+                       Bind(version, dn, passwd, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> Synchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) as an Ldapv3 bind, using the specified name,
+               /// password, and constraints.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// Note: the application should use care in the use
+               /// of String password objects.  These are long lived
+               /// objects, and may expose a security risk, especially
+               /// in objects that are serialized.  The LdapConnection
+               /// keeps no long lived instances of these objects.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">    Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <deprecated> replaced by {@link #bind(int, String, byte[], LdapConstraints)}
+               /// </deprecated>
+               public virtual void  Bind(System.String dn, System.String passwd, LdapConstraints cons)
+               {
+                       Bind(Ldap_V3, dn, passwd, cons);
+                       return ;
+               }
+               
+               /// <summary> Synchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) using the specified name, password, Ldap version,
+               /// and constraints.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="version"> The Ldap protocol version, use Ldap_V3.
+               /// Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">      If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// <br><br>
+               /// Note: the application should use care in the use
+               /// of String password objects.  These are long lived
+               /// objects, and may expose a security risk, especially
+               /// in objects that are serialized.  The LdapConnection
+               /// keeps no long lived instances of these objects.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <deprecated> replaced by
+               /// {@link #bind(int, String, byte[], LdapConstraints)}
+               /// </deprecated>
+               public virtual void  Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
+               {
+                       sbyte[] pw = null;
+                       if ((System.Object) passwd != null)
+                       {
+                               try
+                               {
+                                       System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
+                                       byte[] ibytes = encoder.GetBytes(passwd);
+                                       pw=SupportClass.ToSByteArray(ibytes);
+
+                                       //                                      pw = passwd.getBytes("UTF8");
+                                       passwd = null; // Keep no reference to String object
+                               }
+                               catch (System.IO.IOException ex)
+                               {
+                                       passwd = null; // Keep no reference to String object
+                                       throw new System.SystemException(ex.ToString());
+                               }
+                       }
+                       Bind(version, dn, pw, cons);
+                       return ;
+               }
+               
+               /// <summary> Synchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) using the specified name, password,
+               /// and Ldap version.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="version"> The version of the Ldap protocol to use
+               /// in the bind, use Ldap_V3.  Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               [CLSCompliantAttribute(false)]
+               public virtual void  Bind(int version, System.String dn, sbyte[] passwd)
+               {
+                       Bind(version, dn, passwd, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Synchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) using the specified name, password, Ldap version,
+               /// and constraints.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="version"> The Ldap protocol version, use Ldap_V3.
+               /// Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">      If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               [CLSCompliantAttribute(false)]
+               public virtual void  Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
+               {
+                       LdapResponseQueue queue = Bind(version, dn, passwd, null, cons);
+                       LdapResponse res = (LdapResponse) queue.getResponse();
+                       if (res != null)
+                       {
+                               // Set local copy of responseControls synchronously if any
+                               lock (responseCtlSemaphore)
+                               {
+                                       responseCtls = res.Controls;
+                               }
+                               
+                               chkResultCode(queue, cons, res);
+                       }
+                       return ;
+               }
+               
+               /// <summary> Asynchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) using the specified name, password, Ldap
+               /// version, and queue.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// has already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// 
+               /// </summary>
+               /// <param name="version"> The Ldap protocol version, use Ldap_V3.
+               /// Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">  Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               [CLSCompliantAttribute(false)]
+               public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue)
+               {
+                       return Bind(version, dn, passwd, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously authenticates to the Ldap server (that the object is
+               /// currently connected to) using the specified name, password, Ldap
+               /// version, queue, and constraints.
+               /// 
+               /// <p>If the object has been disconnected from an Ldap server,
+               /// this method attempts to reconnect to the server. If the object
+               /// had already authenticated, the old authentication is discarded.</p>
+               /// 
+               /// </summary>
+               /// <param name="version"> The Ldap protocol version, use Ldap_V3.
+               /// Ldap_V2 is not supported.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">     If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name.
+               /// <br><br>
+               /// </param>
+               /// <param name="passwd"> If non-null and non-empty, specifies that the
+               /// connection and all operations through it should
+               /// be authenticated with dn as the distinguished
+               /// name and passwd as password.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">  Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">     Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               [CLSCompliantAttribute(false)]
+               public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       int msgId;
+                       BindProperties bindProps;
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       if ((System.Object) dn == null)
+                       {
+                               dn = "";
+                       }
+                       else
+                       {
+                               dn = dn.Trim();
+                       }
+                       
+                       if (passwd == null)
+                               passwd = new sbyte[]{};
+                       
+                       bool anonymous = false;
+                       if (passwd.Length == 0)
+                       {
+                               anonymous = true; // anonymous, passwd length zero with simple bind
+                               dn = ""; // set to null if anonymous
+                       }
+
+                       LdapMessage msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
+                       
+                       msgId = msg.MessageID;
+                       bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
+                       
+                       // For bind requests, if not connected, attempt to reconnect
+                       if (!conn.Connected)
+                       {
+                               if ((System.Object) conn.Host != null)
+                               {
+                                       conn.connect(conn.Host, conn.Port);
+                               }
+                               else
+                               {
+                                       throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
+                               }
+                       }
+                       
+                       // The semaphore is released when the bind response is queued.
+                       conn.acquireWriteSemaphore(msgId);
+                       
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
+               }
+               
+               //*************************************************************************
+               // compare methods
+               //*************************************************************************
+               
+               /// <summary> 
+               /// Synchronously checks to see if an entry contains an attribute
+               /// with a specified value.
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to use in the
+               /// comparison.
+               /// <br><br>
+               /// </param>
+               /// <param name="attr">   The attribute to compare against the entry. The
+               /// method checks to see if the entry has an
+               /// attribute with the same name and value as this
+               /// attribute.
+               /// 
+               /// </param>
+               /// <returns> True if the entry has the value,
+               /// and false if the entry does not
+               /// have the value or the attribute.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual bool Compare(System.String dn, LdapAttribute attr)
+               {
+                       return Compare(dn, attr, defSearchCons);
+               }
+               
+               /// <summary> 
+               /// Synchronously checks to see if an entry contains an attribute with a
+               /// specified value, using the specified constraints.
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to use in the
+               /// comparison.
+               /// <br><br>
+               /// </param>
+               /// <param name="attr">   The attribute to compare against the entry. The
+               /// method checks to see if the entry has an
+               /// attribute with the same name and value as this
+               /// attribute.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <returns> True if the entry has the value,
+               /// and false if the entry does not
+               /// have the value or the attribute.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
+               {
+                       bool ret = false;
+                       
+                       LdapResponseQueue queue = Compare(dn, attr, null, cons);
+                       
+                       LdapResponse res = (LdapResponse) queue.getResponse();
+                       
+                       // Set local copy of responseControls synchronously - if there were any
+                       lock (responseCtlSemaphore)
+                       {
+                               responseCtls = res.Controls;
+                       }
+                       
+                       if (res.ResultCode == LdapException.COMPARE_TRUE)
+                       {
+                               ret = true;
+                       }
+                       else if (res.ResultCode == LdapException.COMPARE_FALSE)
+                       {
+                               ret = false;
+                       }
+                       else
+                       {
+                               chkResultCode(queue, cons, res);
+                       }
+                       return ret;
+               }
+               
+               /// <summary> Asynchronously compares an attribute value with one in the directory,
+               /// using the specified queue.
+               /// <p>
+               /// Please note that a successful completion of this command results in
+               /// one of two status codes: LdapException.COMPARE_TRUE if the entry
+               /// has the value, and LdapException.COMPARE_FALSE if the entry
+               /// does not have the value or the attribute.
+               /// <br><br>
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry containing an
+               /// attribute to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="attr">   An attribute to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">  The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <seealso cref="LdapException#COMPARE_TRUE">
+               /// </seealso>
+               /// <seealso cref="LdapException#COMPARE_FALSE">
+               /// </seealso>
+               public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue)
+               {
+                       return Compare(dn, attr, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously compares an attribute value with one in the directory,
+               /// using the specified queue and contraints.
+               /// <p>
+               /// Please note that a successful completion of this command results in
+               /// one of two status codes: LdapException.COMPARE_TRUE if the entry
+               /// has the value, and LdapException.COMPARE_FALSE if the entry
+               /// does not have the value or the attribute.
+               /// <br><br>
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry containing an
+               /// attribute to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="attr">   An attribute to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">    Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">     Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <seealso cref="LdapException#COMPARE_TRUE">
+               /// </seealso>
+               /// <seealso cref="LdapException#COMPARE_FALSE">
+               /// </seealso>
+               public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       if (attr.size() != 1)
+                       {
+                               throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
+                       }
+                       
+                       if ((System.Object) dn == null)
+                       {
+                               // Invalid parameter
+                               throw new System.ArgumentException("compare: DN cannot be null");
+                       }
+                       
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
+                       
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, null);
+               }
+               
+               //*************************************************************************
+               // connect methods
+               //*************************************************************************
+               
+               /// <summary> 
+               /// Connects to the specified host and port.
+               /// 
+               /// <p>If this LdapConnection object represents an open connection, the
+               /// connection is closed first before the new connection is opened.
+               /// At this point, there is no authentication, and any operations are
+               /// conducted as an anonymous client.</p>
+               /// 
+               /// <p> When more than one host name is specified, each host is contacted
+               /// in turn until a connection can be established.</p>
+               /// 
+               /// </summary>
+               /// <param name="host">A host name or a dotted string representing the IP address
+               /// of a host running an Ldap server. It may also
+               /// contain a list of host names, space-delimited. Each host
+               /// name can include a trailing colon and port number.
+               /// <br><br>
+               /// </param>
+               /// <param name="port">The TCP or UDP port number to connect to or contact.
+               /// The default Ldap port is 389. The port parameter is
+               /// ignored for any host hame which includes a colon and
+               /// port number.
+               /// <br><br>
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               public virtual void  Connect(System.String host, int port)
+               {
+                       // connect doesn't affect other clones
+                       // If not a clone, destroys old connection.
+                       // Step through the space-delimited list
+                       SupportClass.Tokenizer hostList = new SupportClass.Tokenizer(host, " ");
+                       System.String address = null;
+                       
+                       int specifiedPort;
+                       int colonIndex; //after the colon is the port
+                       while (hostList.HasMoreTokens())
+                       {
+                               try
+                               {
+                                       specifiedPort = port;
+                                       address = hostList.NextToken();
+                                       colonIndex = address.IndexOf((System.Char) ':');
+                                       if (colonIndex != - 1 && colonIndex + 1 != address.Length)
+                                       {
+                                               //parse Port out of address
+                                               try
+                                               {
+                                                       specifiedPort = System.Int32.Parse(address.Substring(colonIndex + 1));
+                                                       address = address.Substring(0, (colonIndex) - (0));
+                                               }
+                                               catch (System.Exception e)
+                                               {
+                                                       throw new System.ArgumentException(ExceptionMessages.INVALID_ADDRESS);
+                                               }
+                                       }
+                                       // This may return a different conn object
+                                       // Disassociate this clone with the underlying connection.
+                                       conn = conn.destroyClone(true);
+                                       conn.connect(address, specifiedPort);
+                                       break;
+                               }
+                               catch (LdapException LE)
+                               {
+                                       if (!hostList.HasMoreTokens())
+                                               throw LE;
+                               }
+                       }
+                       return ;
+               }
+               
+               //*************************************************************************
+               // delete methods
+               //*************************************************************************
+               
+               /// <summary> 
+               /// Synchronously deletes the entry with the specified distinguished name
+               /// from the directory.
+               /// 
+               /// <p>Note: A Delete operation will not remove an entry that contains
+               /// subordinate entries, nor will it dereference alias entries. </p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to delete.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Delete(System.String dn)
+               {
+                       Delete(dn, defSearchCons);
+                       return ;
+               }
+               
+               
+               /// <summary> Synchronously deletes the entry with the specified distinguished name
+               /// from the directory, using the specified constraints.
+               /// 
+               /// <p>Note: A Delete operation will not remove an entry that contains
+               /// subordinate entries, nor will it dereference alias entries. </p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to delete.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Delete(System.String dn, LdapConstraints cons)
+               {
+                       LdapResponseQueue queue = Delete(dn, null, cons);
+                       
+                       // Get a handle to the delete response
+                       LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
+                       
+                       // Set local copy of responseControls synchronously - if there were any
+                       lock (responseCtlSemaphore)
+                       {
+                               responseCtls = deleteResponse.Controls;
+                       }
+                       chkResultCode(queue, cons, deleteResponse);
+                       return ;
+               }
+               
+               /// <summary> Asynchronously deletes the entry with the specified distinguished name
+               /// from the directory and returns the results to the specified queue.
+               /// 
+               /// <p>Note: A Delete operation will not remove an entry that contains
+               /// subordinate entries, nor will it dereference alias entries. </p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">    The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue)
+               {
+                       return Delete(dn, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously deletes the entry with the specified distinguished name
+               /// from the directory, using the specified contraints and queue.
+               /// 
+               /// <p>Note: A Delete operation will not remove an entry that contains
+               /// subordinate entries, nor will it dereference alias entries. </p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to delete.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">     The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       if ((System.Object) dn == null)
+                       {
+                               // Invalid DN parameter
+                               throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
+                       }
+                       
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       LdapMessage msg = new LdapDeleteRequest(dn, cons.getControls());
+                       
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, null);
+               }
+               
+               //*************************************************************************
+               // disconnect method
+               //*************************************************************************
+               
+               /// <summary> 
+               /// Synchronously disconnects from the Ldap server.
+               /// 
+               /// <p>Before the object can perform Ldap operations again, it must
+               /// reconnect to the server by calling connect.</p>
+               /// 
+               /// <p>The disconnect method abandons any outstanding requests, issues an
+               /// unbind request to the server, and then closes the socket.</p>
+               /// 
+               /// </summary>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               public virtual void  Disconnect()
+               {
+                       // disconnect from API call
+                       Disconnect(defSearchCons, true);
+                       return ;
+               }
+               
+               /// <summary> Synchronously disconnects from the Ldap server.
+               /// 
+               /// <p>Before the object can perform Ldap operations again, it must
+               /// reconnect to the server by calling connect.</p>
+               /// 
+               /// <p>The disconnect method abandons any outstanding requests, issues an
+               /// unbind request to the server, and then closes the socket.</p>
+               /// 
+               /// </summary>
+               /// <param name="cons">LDPConstraints to be set with the unbind request
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Disconnect(LdapConstraints cons)
+               {
+                       // disconnect from API call
+                       Disconnect(cons, true);
+                       return ;
+               }
+               
+               /// <summary> Synchronously disconnect from the server
+               /// 
+               /// </summary>
+               /// <param name="how">true if application call disconnect API, false if finalize.
+               /// </param>
+               private void  Disconnect(LdapConstraints cons, bool how)
+               {
+                       // disconnect doesn't affect other clones
+                       // If not a clone, distroys connection
+                       conn = conn.destroyClone(how);
+                       return ;
+               }
+               
+               //*************************************************************************
+               // extendedOperation methods
+               //*************************************************************************
+               
+               /// <summary> Provides a synchronous means to access extended, non-mandatory
+               /// operations offered by a particular Ldapv3 compliant server.
+               /// 
+               /// </summary>
+               /// <param name="op"> The object which contains (1) an identifier of an extended
+               /// operation which should be recognized by the particular Ldap
+               /// server this client is connected to and (2)
+               /// an operation-specific sequence of octet strings
+               /// or BER-encoded values.
+               /// 
+               /// </param>
+               /// <returns> An operation-specific object, containing an ID and either an octet
+               /// string or BER-encoded values.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op)
+               {
+                       return ExtendedOperation(op, defSearchCons);
+               }
+               
+               /*
+               *  Synchronous Ldap extended request with SearchConstraints
+               */
+               
+               /// <summary> 
+               /// Provides a synchronous means to access extended, non-mandatory
+               /// operations offered by a particular Ldapv3 compliant server.
+               /// 
+               /// </summary>
+               /// <param name="op"> The object which contains (1) an identifier of an extended
+               /// operation which should be recognized by the particular Ldap
+               /// server this client is connected to and (2) an
+               /// operation-specific sequence of octet strings
+               /// or BER-encoded values.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <returns> An operation-specific object, containing an ID and either an
+               /// octet string or BER-encoded values.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               
+               public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
+               {
+                       
+                       // Call asynchronous API and get back handler to reponse queue
+                       LdapResponseQueue queue = ExtendedOperation(op, cons, null);
+                       LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
+                       
+                       // Set local copy of responseControls synchronously - if there were any
+                       lock (responseCtlSemaphore)
+                       {
+                               responseCtls = response.Controls;
+                       }
+                       
+                       chkResultCode(queue, cons, response);
+                       return response;
+               }
+               
+               
+               /*
+               * Asynchronous Ldap extended request
+               */
+               
+               /// <summary> Provides an asynchronous means to access extended, non-mandatory
+               /// operations offered by a particular Ldapv3 compliant server.
+               /// 
+               /// </summary>
+               /// <param name="op"> The object which contains (1) an identifier of an extended
+               /// operation which should be recognized by the particular Ldap
+               /// server this client is connected to and (2) an
+               /// operation-specific sequence of octet strings
+               /// or BER-encoded values.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">    The queue for messages returned from a server in
+               /// response to this request. If it is null, a queue
+               /// object is created internally.
+               /// 
+               /// </param>
+               /// <returns> An operation-specific object, containing an ID and either an octet
+               /// string or BER-encoded values.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               
+               public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapResponseQueue queue)
+               {
+                       
+                       return ExtendedOperation(op, defSearchCons, queue);
+               }
+               
+               
+               /*
+               *  Asynchronous Ldap extended request with SearchConstraints
+               */
+               
+               /// <summary> Provides an asynchronous means to access extended, non-mandatory
+               /// operations offered by a particular Ldapv3 compliant server.
+               /// 
+               /// </summary>
+               /// <param name="op"> The object which contains (1) an identifier of an extended
+               /// operation which should be recognized by the particular Ldap
+               /// server this client is connected to and (2) an operation-
+               /// specific sequence of octet strings or BER-encoded values.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">    The queue for messages returned from a server in
+               /// response to this request. If it is null, a queue
+               /// object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">     The constraints specific to this operation.
+               /// 
+               /// </param>
+               /// <returns> An operation-specific object, containing an ID and either an
+               /// octet string or BER-encoded values.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               
+               public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
+               {
+                       // Use default constraints if none-specified
+                       if (cons == null)
+                               cons = defSearchCons;
+                       LdapMessage msg = MakeExtendedOperation(op, cons);
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, null);
+               }
+               
+               /// <summary> Formulates the extended operation, constraints into an
+               /// LdapMessage and returns the LdapMessage.  This is used by
+               /// extendedOperation and startTLS which needs the LdapMessage to
+               /// get the MessageID.
+               /// </summary>
+               protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
+               {
+                       // Use default constraints if none-specified
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       // error check the parameters
+                       if ((System.Object) op.getID() == null)
+                       {
+                               // Invalid extended operation parameter, no OID specified
+                               throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
+                       }
+                       
+                       return new LdapExtendedRequest(op, cons.getControls());
+               }
+               
+               //*************************************************************************
+               // getResponseControls method
+               //*************************************************************************
+               
+               //*************************************************************************
+               // modify methods
+               //*************************************************************************
+               
+               /// <summary> Synchronously makes a single change to an existing entry in the
+               /// directory.
+               /// 
+               /// <p>For example, this modify method changes the value of an attribute,
+               /// adds a new attribute value, or removes an existing attribute value. </p>
+               /// 
+               /// <p>The LdapModification object specifies both the change to be made and
+               /// the LdapAttribute value to be changed.</p>
+               /// 
+               /// <p>If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modification.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">    The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mod">   A single change to be made to the entry.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Modify(System.String dn, LdapModification mod)
+               {
+                       Modify(dn, mod, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Synchronously makes a single change to an existing entry in the
+               /// directory, using the specified constraints.
+               /// 
+               /// <p>For example, this modify method changes the value of an attribute,
+               /// adds a new attribute value, or removes an existing attribute value.</p>
+               /// 
+               /// <p>The LdapModification object specifies both the change to be
+               /// made and the LdapAttribute value to be changed.</p>
+               /// 
+               /// <p>If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modification.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">      The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mod">     A single change to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">    The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Modify(System.String dn, LdapModification mod, LdapConstraints cons)
+               {
+                       LdapModification[] mods = new LdapModification[1];
+                       mods[0] = mod;
+                       Modify(dn, mods, cons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Synchronously makes a set of changes to an existing entry in the
+               /// directory.
+               /// 
+               /// <p>For example, this modify method changes attribute values, adds
+               /// new attribute values, or removes existing attribute values.</p>
+               /// 
+               /// <p>Because the server applies all changes in an LdapModification array
+               /// atomically, the application can expect that no changes
+               /// have been performed if an error is returned.
+               /// If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modifications.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">    Distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mods">  The changes to be made to the entry.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Modify(System.String dn, LdapModification[] mods)
+               {
+                       Modify(dn, mods, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> Synchronously makes a set of changes to an existing entry in the
+               /// directory, using the specified constraints.
+               /// 
+               /// <p>For example, this modify method changes attribute values, adds new
+               /// attribute values, or removes existing attribute values.</p>
+               /// 
+               /// <p>Because the server applies all changes in an LdapModification array
+               /// atomically, the application can expect that no changes
+               /// have been performed if an error is returned.
+               /// If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modifications.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">     The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mods">   The changes to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">   The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an
+               /// error message and an Ldap error code.
+               /// </exception>
+               public virtual void  Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
+               {
+                       LdapResponseQueue queue = Modify(dn, mods, null, cons);
+                       
+                       // Get a handle to the modify response
+                       LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
+                       
+                       // Set local copy of responseControls synchronously - if there were any
+                       lock (responseCtlSemaphore)
+                       {
+                               responseCtls = modifyResponse.Controls;
+                       }
+                       
+                       chkResultCode(queue, cons, modifyResponse);
+                       
+                       return ;
+               }
+               
+               /// <summary> Asynchronously makes a single change to an existing entry in the
+               /// directory.
+               /// 
+               /// <p>For example, this modify method can change the value of an attribute,
+               /// add a new attribute value, or remove an existing attribute value.</p>
+               /// 
+               /// <p>The LdapModification object specifies both the change to be made and
+               /// the LdapAttribute value to be changed.</p>
+               /// 
+               /// <p>If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modification.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">        Distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mod">       A single change to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">     Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue)
+               {
+                       return Modify(dn, mod, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously makes a single change to an existing entry in the
+               /// directory, using the specified constraints and queue.
+               /// 
+               /// <p>For example, this modify method can change the value of an attribute,
+               /// add a new attribute value, or remove an existing attribute value.</p>
+               /// 
+               /// <p>The LdapModification object specifies both the change to be made
+               /// and the LdapAttribute value to be changed.</p>
+               /// 
+               /// <p>If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modification.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">         Distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mod">        A single change to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">      Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">       Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       LdapModification[] mods = new LdapModification[1];
+                       mods[0] = mod;
+                       return Modify(dn, mods, queue, cons);
+               }
+               
+               /// <summary> Asynchronously makes a set of changes to an existing entry in the
+               /// directory.
+               /// 
+               /// <p>For example, this modify method can change attribute values, add new
+               /// attribute values, or remove existing attribute values.</p>
+               /// 
+               /// <p>Because the server applies all changes in an LdapModification array
+               /// atomically, the application can expect that no changes
+               /// have been performed if an error is returned.
+               /// If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modifications.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">        The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mods">      The changes to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">     The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue)
+               {
+                       return Modify(dn, mods, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously makes a set of changes to an existing entry in the
+               /// directory, using the specified constraints and queue.
+               /// 
+               /// <p>For example, this modify method can change attribute values, add new
+               /// attribute values, or remove existing attribute values.</p>
+               /// 
+               /// <p>Because the server applies all changes in an LdapModification array
+               /// atomically, the application can expect that no changes
+               /// have been performed if an error is returned.
+               /// If the request fails with {@link LdapException#CONNECT_ERROR},
+               /// it is indeterminate whether or not the server made the modifications.</p>
+               /// 
+               /// </summary>
+               /// <param name="dn">        The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mods">      The changes to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">     The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">      Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       if ((System.Object) dn == null)
+                       {
+                               // Invalid DN parameter
+                               throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
+                       }
+                       
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
+                       
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, null);
+               }
+               
+               //*************************************************************************
+               // read methods
+               //*************************************************************************
+               
+               /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
+               /// and retrieves all attributes for the entry.
+               /// 
+               /// </summary>
+               /// <param name="dn">       The distinguished name of the entry to retrieve.
+               /// 
+               /// </param>
+               /// <returns> the LdapEntry read from the server.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException if the object was not found
+               /// </exception>
+               public virtual LdapEntry Read(System.String dn)
+               {
+                       return Read(dn, defSearchCons);
+               }
+               
+               
+               /// <summary> 
+               /// Synchronously reads the entry for the specified distiguished name (DN),
+               /// using the specified constraints, and retrieves all attributes for the
+               /// entry.
+               /// 
+               /// </summary>
+               /// <param name="dn">        The distinguished name of the entry to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">      The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <returns> the LdapEntry read from the server
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException if the object was not found
+               /// </exception>
+               public virtual LdapEntry Read(System.String dn, LdapSearchConstraints cons)
+               {
+                       return Read(dn, null, cons);
+               }
+               
+               /// <summary> 
+               /// Synchronously reads the entry for the specified distinguished name (DN)
+               /// and retrieves only the specified attributes from the entry.
+               /// 
+               /// </summary>
+               /// <param name="dn">        The distinguished name of the entry to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">     The names of the attributes to retrieve.
+               /// 
+               /// </param>
+               /// <returns> the LdapEntry read from the server
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException if the object was not found
+               /// </exception>
+               public virtual LdapEntry Read(System.String dn, System.String[] attrs)
+               {
+                       return Read(dn, attrs, defSearchCons);
+               }
+               
+               /// <summary> Synchronously reads the entry for the specified distinguished name (DN),
+               /// using the specified constraints, and retrieves only the specified
+               /// attributes from the entry.
+               /// 
+               /// </summary>
+               /// <param name="dn">      The distinguished name of the entry to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">   The names of the attributes to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">    The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <returns> the LdapEntry read from the server
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException if the object was not found
+               /// </exception>
+               public virtual LdapEntry Read(System.String dn, System.String[] attrs, LdapSearchConstraints cons)
+               {
+                       LdapSearchResults sr = Search(dn, SCOPE_BASE, null, attrs, false, cons);
+                       
+                       LdapEntry ret = null;
+                       if (sr.hasMore())
+                       {
+                               ret = sr.next();
+                               if (sr.hasMore())
+                               {
+                                       // "Read response is ambiguous, multiple entries returned"
+                                       throw new LdapLocalException(ExceptionMessages.READ_MULTIPLE, LdapException.AMBIGUOUS_RESPONSE);
+                               }
+                       }
+                       return ret;
+               }
+               
+               /// <summary> Synchronously reads the entry specified by the Ldap URL.
+               /// 
+               /// <p>When this read method is called, a new connection is created
+               /// automatically, using the host and port specified in the URL. After
+               /// finding the entry, the method closes the connection (in other words,
+               /// it disconnects from the Ldap server).</p>
+               /// 
+               /// <p>If the URL specifies a filter and scope, they are not used. Of the
+               /// information specified in the URL, this method only uses the Ldap host
+               /// name and port number, the base distinguished name (DN), and the list
+               /// of attributes to return.</p>
+               /// 
+               /// </summary>
+               /// <param name="toGet">          Ldap URL specifying the entry to read.
+               /// 
+               /// </param>
+               /// <returns> The entry specified by the base DN.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException if the object was not found
+               /// </exception>
+               public static LdapEntry Read(LdapUrl toGet)
+               {
+                       LdapConnection lconn = new LdapConnection();
+                       lconn.Connect(toGet.Host, toGet.Port);
+                       LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray);
+                       lconn.Disconnect();
+                       return toReturn;
+               }
+               
+               /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
+               /// specified constraints.
+               /// 
+               /// <p>When this method is called, a new connection is created
+               /// automatically, using the host and port specified in the URL. After
+               /// finding the entry, the method closes the connection (in other words,
+               /// it disconnects from the Ldap server).</p>
+               /// 
+               /// <p>If the URL specifies a filter and scope, they are not used. Of the
+               /// information specified in the URL, this method only uses the Ldap host
+               /// name and port number, the base distinguished name (DN), and the list
+               /// of attributes to return.</p>
+               /// 
+               /// </summary>
+               /// <returns> The entry specified by the base DN.
+               /// 
+               /// </returns>
+               /// <param name="toGet">      Ldap URL specifying the entry to read.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">      Constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException if the object was not found
+               /// </exception>
+               public static LdapEntry Read(LdapUrl toGet, LdapSearchConstraints cons)
+               {
+                       LdapConnection lconn = new LdapConnection();
+                       lconn.Connect(toGet.Host, toGet.Port);
+                       LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray, cons);
+                       lconn.Disconnect();
+                       return toReturn;
+               }
+               
+               //*************************************************************************
+               // rename methods
+               //*************************************************************************
+               
+               /// <summary> 
+               /// Synchronously renames an existing entry in the directory.
+               /// 
+               /// </summary>
+               /// <param name="dn">      The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">  The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Rename(System.String dn, System.String newRdn, bool deleteOldRdn)
+               {
+                       Rename(dn, newRdn, deleteOldRdn, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Synchronously renames an existing entry in the directory, using the
+               /// specified constraints.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
+               {
+                       // null for newParentdn means that this is originating as an Ldapv2 call
+                       Rename(dn, newRdn, null, deleteOldRdn, cons);
+                       return ;
+               }
+               
+               /// <summary> Synchronously renames an existing entry in the directory, possibly
+               /// repositioning the entry in the directory tree.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newParentdn">   The distinguished name of an existing entry which
+               /// is to be the new parent of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn)
+               {
+                       Rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
+                       return ;
+               }
+               
+               /// <summary> 
+               /// Synchronously renames an existing entry in the directory, using the
+               /// specified constraints and possibly repositioning the entry in the
+               /// directory tree.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newParentdn">   The distinguished name of an existing entry which
+               /// is to be the new parent of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual void  Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
+               {
+                       LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
+                       
+                       // Get a handle to the rename response
+                       LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
+                       
+                       // Set local copy of responseControls synchronously - if there were any
+                       lock (responseCtlSemaphore)
+                       {
+                               responseCtls = renameResponse.Controls;
+                       }
+                       
+                       chkResultCode(queue, cons, renameResponse);
+                       return ;
+               }
+               
+               /*
+               * rename
+               */
+               
+               /// <summary> Asynchronously renames an existing entry in the directory.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">         The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue)
+               {
+                       return Rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously renames an existing entry in the directory, using the
+               /// specified constraints.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">         The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
+               }
+               
+               /// <summary> Asynchronously renames an existing entry in the directory, possibly
+               /// repositioning the entry in the directory.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newParentdn">   The distinguished name of an existing entry which
+               /// is to be the new parent of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">         The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue)
+               {
+                       return Rename(dn, newRdn, newParentdn, deleteOldRdn, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously renames an existing entry in the directory, using the
+               /// specified constraints and possibily repositioning the entry in the
+               /// directory.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newParentdn">   The distinguished name of an existing entry which
+               /// is to be the new parent of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">         The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the operation.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
+               {
+                       if ((System.Object) dn == null || (System.Object) newRdn == null)
+                       {
+                               // Invalid DN or RDN parameter
+                               throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
+                       }
+                       
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
+                       
+                       return SendRequestToServer(msg, cons.TimeLimit, queue, null);
+               }
+               
+               //*************************************************************************
+               // search methods
+               //*************************************************************************
+               
+               /// <summary> 
+               /// Synchronously performs the search specified by the parameters.
+               /// 
+               /// </summary>
+               /// <param name="base">          The base distinguished name to search from.
+               /// <br><br>
+               /// </param>
+               /// <param name="scope">         The scope of the entries to search. The following
+               /// are the valid options:
+               /// <ul>
+               /// <li>SCOPE_BASE - searches only the base DN
+               /// 
+               /// <li>SCOPE_ONE - searches only entries under the base DN
+               /// 
+               /// <li>SCOPE_SUB - searches the base DN and all entries
+               /// within its subtree
+               /// </ul><br><br>
+               /// </param>
+               /// <param name="filter">        Search filter specifying the search criteria.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">         Names of attributes to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="typesOnly">     If true, returns the names but not the values of
+               /// the attributes found. If false, returns the
+               /// names and values for attributes found.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly)
+               {
+                       return Search(base_Renamed, scope, filter, attrs, typesOnly, defSearchCons);
+               }
+               
+               /// <summary> 
+               /// Synchronously performs the search specified by the parameters,
+               /// using the specified search constraints (such as the
+               /// maximum number of entries to find or the maximum time to wait for
+               /// search results).
+               /// 
+               /// <p>As part of the search constraints, the method allows specifying
+               /// whether or not the results are to be delivered all at once or in
+               /// smaller batches. If specified that the results are to be delivered in
+               /// smaller batches, each iteration blocks only until the next batch of
+               /// results is returned.</p>
+               /// 
+               /// </summary>
+               /// <param name="base">          The base distinguished name to search from.
+               /// <br><br>
+               /// </param>
+               /// <param name="scope">         The scope of the entries to search. The following
+               /// are the valid options:
+               /// <ul>
+               /// <li>SCOPE_BASE - searches only the base DN
+               /// 
+               /// <li>SCOPE_ONE - searches only entries under the base DN
+               /// 
+               /// <li>SCOPE_SUB - searches the base DN and all entries
+               /// within its subtree
+               /// </ul><br><br>
+               /// </param>
+               /// <param name="filter">        The search filter specifying the search criteria.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">         The names of attributes to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="typesOnly">     If true, returns the names but not the values of
+               /// the attributes found.  If false, returns the
+               /// names and values for attributes found.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the search.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchConstraints cons)
+               {
+                       LdapSearchQueue queue = Search(base_Renamed, scope, filter, attrs, typesOnly, null, cons);
+                       
+                       if (cons == null)
+                               cons = defSearchCons;
+                       return new LdapSearchResults(this, queue, cons);
+               }
+               
+               /// <summary> Asynchronously performs the search specified by the parameters.
+               /// 
+               /// </summary>
+               /// <param name="base">          The base distinguished name to search from.
+               /// <br><br>
+               /// </param>
+               /// <param name="scope">         The scope of the entries to search. The following
+               /// are the valid options:
+               /// <ul>
+               /// <li>SCOPE_BASE - searches only the base DN
+               /// 
+               /// <li>SCOPE_ONE - searches only entries under the base DN
+               /// 
+               /// <li>SCOPE_SUB - searches the base DN and all entries
+               /// within its subtree
+               /// </ul><br><br>
+               /// </param>
+               /// <param name="filter">        Search filter specifying the search criteria.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">         Names of attributes to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="typesOnly">     If true, returns the names but not the values of
+               /// the attributes found.  If false, returns the
+               /// names and values for attributes found.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">         Handler for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue)
+               {
+                       return Search(base_Renamed, scope, filter, attrs, typesOnly, queue, defSearchCons);
+               }
+               
+               /// <summary> Asynchronously performs the search specified by the parameters,
+               /// also allowing specification of constraints for the search (such
+               /// as the maximum number of entries to find or the maximum time to
+               /// wait for search results).
+               /// 
+               /// </summary>
+               /// <param name="base">          The base distinguished name to search from.
+               /// <br><br>
+               /// </param>
+               /// <param name="scope">         The scope of the entries to search. The following
+               /// are the valid options:
+               /// <ul>
+               /// <li>SCOPE_BASE - searches only the base DN
+               /// 
+               /// <li>SCOPE_ONE - searches only entries under the base DN
+               /// 
+               /// <li>SCOPE_SUB - searches the base DN and all entries
+               /// within its subtree
+               /// </ul><br><br>
+               /// </param>
+               /// <param name="filter">        The search filter specifying the search criteria.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">         The names of attributes to retrieve.
+               /// <br><br>
+               /// </param>
+               /// <param name="typesOnly">     If true, returns the names but not the values of
+               /// the attributes found.  If false, returns the
+               /// names and values for attributes found.
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">         The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the search.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue, LdapSearchConstraints cons)
+               {
+                       if ((System.Object) filter == null)
+                       {
+                               filter = "objectclass=*";
+                       }
+                       if (cons == null)
+                               cons = defSearchCons;
+                       
+                       LdapMessage msg = new LdapSearchRequest(base_Renamed, scope, filter, attrs, cons.Dereference, cons.MaxResults, cons.ServerTimeLimit, typesOnly, cons.getControls());
+                       MessageAgent agent;
+                       LdapSearchQueue myqueue = queue;
+                       if (myqueue == null)
+                       {
+                               agent = new MessageAgent();
+                               myqueue = new LdapSearchQueue(agent);
+                       }
+                       else
+                       {
+                               agent = queue.MessageAgent;
+                       }
+                       
+                       try
+                       {
+                               agent.sendMessage(conn, msg, cons.TimeLimit, myqueue, null);
+                       }
+                       catch (LdapException lex)
+                       {
+                               throw lex;
+                       }
+                       return myqueue;
+               }
+               
+               /*
+               * Ldap URL search
+               */
+               
+               /// <summary> Synchronously performs the search specified by the Ldap URL, returning
+               /// an enumerable LdapSearchResults object.
+               /// 
+               /// </summary>
+               /// <param name="toGet">The Ldap URL specifying the entry to read.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public static LdapSearchResults Search(LdapUrl toGet)
+               {
+                       // Get a clone of default search constraints, method alters batchSize
+                       return Search(toGet, null);
+               }
+               
+               /*
+               * Ldap URL search
+               */
+               
+               /// <summary> Synchronously perfoms the search specified by the Ldap URL, using
+               /// the specified search constraints (such as the maximum number of
+               /// entries to find or the maximum time to wait for search results).
+               /// 
+               /// <p>When this method is called, a new connection is created
+               /// automatically, using the host and port specified in the URL. After
+               /// all search results have been received from the server, the method
+               /// closes the connection (in other words, it disconnects from the Ldap
+               /// server).</p>
+               /// 
+               /// <p>As part of the search constraints, a choice can be made as to whether
+               /// to have the results delivered all at once or in smaller batches. If
+               /// the results are to be delivered in smaller batches, each iteration
+               /// blocks only until the next batch of results is returned.</p>
+               /// 
+               /// 
+               /// </summary>
+               /// <param name="toGet">         Ldap URL specifying the entry to read.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">          The constraints specific to the search.
+               /// 
+               /// </param>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public static LdapSearchResults Search(LdapUrl toGet, LdapSearchConstraints cons)
+               {
+                       LdapConnection lconn = new LdapConnection();
+                       lconn.Connect(toGet.Host, toGet.Port);
+                       if (cons == null)
+                       {
+                               // This is a clone, so we already have our own copy
+                               cons = lconn.SearchConstraints;
+                       }
+                       else
+                       {
+                               // get our own copy of user's constraints because we modify it
+                               cons = (LdapSearchConstraints) cons.Clone();
+                       }
+                       cons.BatchSize = 0; // Must wait until all results arrive
+                       LdapSearchResults toReturn = lconn.Search(toGet.getDN(), toGet.Scope, toGet.Filter, toGet.AttributeArray, false, cons);
+                       lconn.Disconnect();
+                       return toReturn;
+               }
+               
+               /// <summary> Sends an Ldap request to a directory server.
+               /// 
+               /// <p>The specified the Ldap request is sent to the directory server
+               /// associated with this connection using default constraints. An Ldap
+               /// request object is a subclass {@link LdapMessage} with the operation
+               /// type set to one of the request types. You can build a request by using
+               /// the request classes found in this package</p>
+               /// 
+               /// <p>You should note that, since Ldap requests sent to the server
+               /// using sendRequest are asynchronous, automatic referral following
+               /// does not apply to these requests.</p>
+               /// 
+               /// </summary>
+               /// <param name="request">The Ldap request to send to the directory server.
+               /// </param>
+               /// <param name="queue">   The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// </param>
+               /// <exception cref="">     LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <seealso cref="LdapMessage#getType()">
+               /// </seealso>
+               /// <seealso cref="LdapMessage#isRequest()">
+               /// </seealso>
+               public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue)
+               {
+                       return SendRequest(request, queue, null);
+               }
+               
+               /// <summary> Sends an Ldap request to a directory server.
+               /// 
+               /// <p>The specified the Ldap request is sent to the directory server
+               /// associated with this connection. An Ldap request object is an
+               /// {@link LdapMessage} with the operation type set to one of the request
+               /// types. You can build a request by using the request classes found in this
+               /// package</p>
+               /// 
+               /// <p>You should note that, since Ldap requests sent to the server
+               /// using sendRequest are asynchronous, automatic referral following
+               /// does not apply to these requests.</p>
+               /// 
+               /// </summary>
+               /// <param name="request">The Ldap request to send to the directory server.
+               /// </param>
+               /// <param name="queue">   The queue for messages returned from a server in
+               /// response to this request. If it is null, a
+               /// queue object is created internally.
+               /// </param>
+               /// <param name="cons">   The constraints that apply to this request
+               /// </param>
+               /// <exception cref="">     LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// 
+               /// </exception>
+               /// <seealso cref="LdapMessage#getType()">
+               /// </seealso>
+               /// <seealso cref="LdapMessage#isRequest()">
+               /// </seealso>
+               public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
+               {
+                       
+                       
+                       if (!request.Request)
+                       {
+                               throw new System.SystemException("Object is not a request message");
+                       }
+                       
+                       if (cons == null)
+                       {
+                               cons = defSearchCons;
+                       }
+                       
+                       // Get the correct queue for a search request
+                       MessageAgent agent;
+                       LdapMessageQueue myqueue = queue;
+                       if (myqueue == null)
+                       {
+                               agent = new MessageAgent();
+                               if (request.Type == LdapMessage.SEARCH_REQUEST)
+                               {
+                                       myqueue = new LdapSearchQueue(agent);
+                               }
+                               else
+                               {
+                                       myqueue = new LdapResponseQueue(agent);
+                               }
+                       }
+                       else
+                       {
+                               if (request.Type == LdapMessage.SEARCH_REQUEST)
+                               {
+                                       agent = queue.MessageAgent;
+                               }
+                               else
+                               {
+                                       agent = queue.MessageAgent;
+                               }
+                       }
+                       
+                       try
+                       {
+                               agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
+                       }
+                       catch (LdapException lex)
+                       {
+                               throw lex;
+                       }
+                       return myqueue;
+               }
+               
+               //*************************************************************************
+               // helper methods
+               //*************************************************************************
+               
+               /// <summary> Locates the appropriate message agent and sends
+               /// the Ldap request to a directory server.
+               /// 
+               /// </summary>
+               /// <param name="msg">the message to send
+               /// <br><br>
+               /// </param>
+               /// <param name="timeout">the timeout value
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">the response queue or null
+               /// 
+               /// </param>
+               /// <returns> the LdapResponseQueue for this request
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               private LdapResponseQueue SendRequestToServer(LdapMessage msg, int timeout, LdapResponseQueue queue, BindProperties bindProps)
+               {
+                       MessageAgent agent;
+                       if (queue == null)
+                       {
+                               agent = new MessageAgent();
+                               queue = new LdapResponseQueue(agent);
+                       }
+                       else
+                       {
+                               agent = queue.MessageAgent;
+                       }
+                       
+                       agent.sendMessage(conn, msg, timeout, queue, bindProps);
+                       return queue;
+               }
+               
+               /// <summary> get an LdapConnection object so that we can follow a referral.
+               /// This function is never called if cons.getReferralFollowing() returns
+               /// false.
+               /// 
+               /// </summary>
+               /// <param name="referrals">the array of referral strings
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <returns> The referralInfo object
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapReferralException A general exception which includes
+               /// an error message and an Ldap error code.
+               /// </exception>
+               private ReferralInfo getReferralConnection(System.String[] referrals)
+               {
+                       ReferralInfo refInfo = null;
+                       System.Exception ex = null;
+                       LdapConnection rconn = null;
+                       LdapReferralHandler rh = defSearchCons.getReferralHandler();
+                       int i = 0;
+                       // Check if we use LdapRebind to get authentication credentials
+                       if ((rh == null) || (rh is LdapAuthHandler))
+                       {
+                               for (i = 0; i < referrals.Length; i++)
+                               {
+                                       // dn, pw are null in the default case (anonymous bind)
+                                       System.String dn = null;
+                                       sbyte[] pw = null;
+                                       try
+                                       {
+                                               rconn = new LdapConnection();
+                                               rconn.Constraints = defSearchCons;
+                                               LdapUrl url = new LdapUrl(referrals[i]);
+                                               rconn.Connect(url.Host, url.Port);
+                                               if (rh != null)
+                                               {
+                                                       if (rh is LdapAuthHandler)
+                                                       {
+                                                               // Get application supplied dn and pw
+                                                               LdapAuthProvider ap = ((LdapAuthHandler) rh).getAuthProvider(url.Host, url.Port);
+                                                               dn = ap.DN;
+                                                               pw = ap.Password;
+                                                       }
+                                               }
+                                               rconn.Bind(Ldap_V3, dn, pw);
+                                               ex = null;
+                                               refInfo = new ReferralInfo(rconn, referrals, url);
+                                               // Indicate this connection created to follow referral
+                                               rconn.Connection.ActiveReferral = refInfo;
+                                               break;
+                                       }
+                                       catch (System.Exception lex)
+                                       {
+                                               if (rconn != null)
+                                               {
+                                                       try
+                                                       {
+                                                               rconn.Disconnect();
+                                                               rconn = null;
+                                                               ex = lex;
+                                                       }
+                                                       catch (LdapException e)
+                                                       {
+                                                               ; // ignore
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                               // Check if application gets connection and does bind
+                       else
+                       {
+                               //  rh instanceof LdapBind
+                               try
+                               {
+                                       rconn = ((LdapBindHandler) rh).Bind(referrals, this);
+                                       if (rconn == null)
+                                       {
+                                               LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR);
+                                               rex.setReferrals(referrals);
+                                               throw rex;
+                                       }
+                                       // Figure out which Url belongs to the connection
+                                       for (int idx = 0; idx < referrals.Length; idx++)
+                                       {
+                                               try
+                                               {
+                                                       LdapUrl url = new LdapUrl(referrals[idx]);
+                                                       if (url.Host.ToUpper().Equals(rconn.Host.ToUpper()) && (url.Port == rconn.Port))
+                                                       {
+                                                               refInfo = new ReferralInfo(rconn, referrals, url);
+                                                               break;
+                                                       }
+                                               }
+                                               catch (System.Exception e)
+                                               {
+                                                       ; // ignore
+                                               }
+                                       }
+                                       if (refInfo == null)
+                                       {
+                                               // Could not match LdapBind.bind() connecction with URL list
+                                               ex = new LdapLocalException(ExceptionMessages.REFERRAL_BIND_MATCH, LdapException.CONNECT_ERROR);
+                                       }
+                               }
+                               catch (System.Exception lex)
+                               {
+                                       rconn = null;
+                                       ex = lex;
+                               }
+                       }
+                       if (ex != null)
+                       {
+                               // Could not connect to any server, throw an exception
+                               LdapException ldapex;
+                               if (ex is LdapReferralException)
+                               {
+                                       throw (LdapReferralException) ex;
+                               }
+                               else if (ex is LdapException)
+                               {
+                                       ldapex = (LdapException) ex;
+                               }
+                               else
+                               {
+                                       ldapex = new LdapLocalException(ExceptionMessages.SERVER_CONNECT_ERROR, new System.Object[]{conn.Host}, LdapException.CONNECT_ERROR, ex);
+                               }
+                               // Error attempting to follow a referral
+                               LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ldapex);
+                               rex.setReferrals(referrals);
+                               // Use last URL string for the failed referral
+                               rex.FailedReferral = referrals[referrals.Length - 1];
+                               throw rex;
+                       }
+                       
+                       // We now have an authenticated connection
+                       // to be used to follow the referral.
+                       return refInfo;
+               }
+               
+               /// <summary> Check the result code and throw an exception if needed.
+               /// 
+               /// <p>If referral following is enabled, checks if we need to
+               /// follow a referral</p>
+               /// 
+               /// </summary>
+               /// <param name="queue">- the message queue of the current response
+               /// 
+               /// </param>
+               /// <param name="cons">- the constraints that apply to the request
+               /// 
+               /// </param>
+               /// <param name="response">- the LdapResponse to check
+               /// </param>
+               private void  chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
+               {
+                       if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
+                       {
+                               // Perform referral following and return
+                               System.Collections.ArrayList refConn = null;
+                               try
+                               {
+                                       chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
+                               }
+                               finally
+                               {
+                                       releaseReferralConnections(refConn);
+                               }
+                       }
+                       else
+                       {
+                               // Throws exception for non success result
+                               response.chkResultCode();
+                       }
+                       return ;
+               }
+               
+               /// <summary> Follow referrals if necessary referral following enabled.
+               /// This function is called only by synchronous requests.
+               /// Search responses come here only if referral following is
+               /// enabled and if we are processing a SearchResultReference
+               /// or a Response with a status of REFERRAL, i.e. we are
+               /// going to follow a referral.
+               /// 
+               /// This functions recursively follows a referral until a result
+               /// is returned or until the hop limit is reached.
+               /// 
+               /// </summary>
+               /// <param name="queue">The LdapResponseQueue for this request
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">The constraints that apply to the request
+               /// <br><br>
+               /// </param>
+               /// <param name="msg">The referral or search reference response message
+               /// <br><br>
+               /// </param>
+               /// <param name="initialReferrals">The referral array returned from the
+               /// initial request.
+               /// <br><br>
+               /// </param>
+               /// <param name="hopCount">the number of hops already used while
+               /// following this referral
+               /// <br><br>
+               /// </param>
+               /// <param name="searchReference">true if the message is a search reference
+               /// <br><br>
+               /// </param>
+               /// <param name="connectionList">An optional array list used to store
+               /// the LdapConnection objects used in following the referral.
+               /// 
+               /// </param>
+               /// <returns> The array list used to store the all LdapConnection objects
+               /// used in following the referral.  The list will be empty
+               /// if there were none.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               /* package */
+               internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
+               {
+                       System.Collections.ArrayList connList = connectionList;
+                       LdapConnection rconn = null; // new conn for following referral
+                       ReferralInfo rinfo = null; // referral info
+                       LdapMessage origMsg;
+                       
+                       // Get a place to store new connections
+                       if (connList == null)
+                       {
+                               connList = new System.Collections.ArrayList(cons.HopLimit);
+                       }
+                       // Following referrals or search reference
+                       System.String[] refs; // referral list
+                       if (initialReferrals != null)
+                       {
+                               // Search continuation reference from a search request
+                               refs = initialReferrals;
+                               origMsg = msg.RequestingMessage;
+                       }
+                       else
+                       {
+                               // Not a search request
+                               LdapResponse resp = (LdapResponse) queue.getResponse();
+                               if (resp.ResultCode != LdapException.REFERRAL)
+                               {
+                                       // Not referral result,throw Exception if nonzero result
+                                       resp.chkResultCode();
+                                       return connList;
+                               }
+                               // We have a referral response
+                               refs = resp.Referrals;
+                               origMsg = resp.RequestingMessage;
+                       }
+                       LdapUrl refUrl; // referral represented as URL
+                       try
+                       {
+                               // increment hop count, check max hops
+                               if (hopCount++ > cons.HopLimit)
+                               {
+                                       throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
+                               }
+                               // Get a connection to follow the referral
+                               rinfo = getReferralConnection(refs);
+                               rconn = rinfo.ReferralConnection;
+                               refUrl = rinfo.ReferralUrl;
+                               connList.Add(rconn);
+                               
+                               
+                               // rebuild msg into new msg changing msgID,dn,scope,filter
+                               LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
+                               
+                               
+                               // Send new message on new connection
+                               try
+                               {
+                                       MessageAgent agent;
+                                       if (queue is LdapResponseQueue)
+                                       {
+                                               agent = queue.MessageAgent;
+                                       }
+                                       else
+                                       {
+                                               agent = queue.MessageAgent;
+                                       }
+                                       agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
+                               }
+                               catch (InterThreadException ex)
+                               {
+                                       // Error ending request to referred server
+                                       LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
+                                       rex.setReferrals(initialReferrals);
+                                       ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
+                                       rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
+                                       throw rex;
+                               }
+                               
+                               if (initialReferrals == null)
+                               {
+                                       // For operation results, when all responses are complete,
+                                       // the stack unwinds back to the original and returns
+                                       // to the application.
+                                       // An exception is thrown for an error
+                                       connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
+                               }
+                               else
+                               {
+                                       // For search, just return to LdapSearchResults object
+                                       return connList;
+                               }
+                       }
+                       catch (System.Exception ex)
+                       {
+                               
+                               if (ex is LdapReferralException)
+                               {
+                                       throw (LdapReferralException) ex;
+                               }
+                               else
+                               {
+                                       
+                                       // Set referral list and failed referral
+                                       LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
+                                       rex.setReferrals(refs);
+                                       if (rinfo != null)
+                                       {
+                                               rex.FailedReferral = rinfo.ReferralUrl.ToString();
+                                       }
+                                       else
+                                       {
+                                               rex.FailedReferral = refs[refs.Length - 1];
+                                       }
+                                       throw rex;
+                               }
+                       }
+                       return connList;
+               }
+               
+               /// <summary> Builds a new request replacing dn, scope, and filter where approprate
+               /// 
+               /// </summary>
+               /// <param name="msg">the original LdapMessage to build the new request from
+               /// <br><br>
+               /// </param>
+               /// <param name="url">the referral url
+               /// 
+               /// </param>
+               /// <returns> a new LdapMessage with appropriate information replaced
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               private LdapMessage rebuildRequest(LdapMessage msg, LdapUrl url, bool reference)
+               {
+                       
+                       System.String dn = url.getDN(); // new base
+                       System.String filter = null;
+                       
+                       switch (msg.Type)
+                       {
+                               
+                               case LdapMessage.SEARCH_REQUEST: 
+                                       if (reference)
+                                       {
+                                               filter = url.Filter;
+                                       }
+                                       break;
+                                       // We are allowed to get a referral for the following
+                               
+                               case LdapMessage.ADD_REQUEST: 
+                               case LdapMessage.BIND_REQUEST: 
+                               case LdapMessage.COMPARE_REQUEST: 
+                               case LdapMessage.DEL_REQUEST: 
+                               case LdapMessage.EXTENDED_REQUEST: 
+                               case LdapMessage.MODIFY_RDN_REQUEST: 
+                               case LdapMessage.MODIFY_REQUEST: 
+                                       break;
+                                       // The following return no response
+                               
+                               case LdapMessage.ABANDON_REQUEST: 
+                               case LdapMessage.UNBIND_REQUEST: 
+                               default: 
+                                       throw new LdapLocalException(ExceptionMessages.IMPROPER_REFERRAL, new System.Object[]{msg.Type}, LdapException.LOCAL_ERROR);
+                       }
+                       
+                       return msg.Clone(dn, filter, reference);
+               }
+               
+               /*
+               * Release connections acquired by following referrals
+               *
+               * @param list the list of the connections
+               */
+               /* package */
+               internal virtual void  releaseReferralConnections(System.Collections.ArrayList list)
+               {
+                       if (list == null)
+                       {
+                               return ;
+                       }
+                       // Release referral connections
+                       for (int i = list.Count - 1; i >= 0; i--)
+                       {
+                               LdapConnection rconn = null;
+                               try
+                               {
+                                       rconn=(LdapConnection)list[i];
+                                       list.RemoveAt(i);
+//                                     rconn = (LdapConnection) list.RemoveAt(i);
+                                       rconn.Disconnect();
+                               }
+                               catch (System.IndexOutOfRangeException ex)
+                               {
+                                       continue;
+                               }
+                               catch (LdapException lex)
+                               {
+                                       continue;
+                               }
+                       }
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConstraints.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConstraints.cs
new file mode 100755 (executable)
index 0000000..aa65fd3
--- /dev/null
@@ -0,0 +1,465 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapConstraints.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Defines options controlling Ldap operations on the directory.
+       /// 
+       /// <p>An LdapConstraints object is always associated with an LdapConnection
+       /// object; its values can be changed with LdapConnection.setConstraints, or
+       /// overridden by passing an LdapConstraints object to an operation.</p>
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#setConstraints(LdapConstraints)">
+       /// </seealso>
+       public class LdapConstraints : System.ICloneable
+       {
+               /// <summary> Returns the maximum number of referrals to follow during automatic
+               /// referral following.  The operation will be abandoned and terminated by
+               /// the API with a result code of LdapException.REFERRAL_LIMIT_EXCEEDED
+               /// if the number of referrals in a sequence exceeds the limit.
+               /// It is ignored for asynchronous operations.
+               /// 
+               /// </summary>
+               /// <returns> The maximum number of referrals to follow in sequence
+               /// 
+               /// </returns>
+               /// <seealso cref="#setHopLimit(int)">
+               /// </seealso>
+               /// <seealso cref="LdapException#REFERRAL_LIMIT_EXCEEDED">
+               /// </seealso>
+               /// <summary> Sets the maximum number of referrals to follow in sequence during
+               /// automatic referral following.
+               /// 
+               /// </summary>
+               /// <param name="hop_limit">The maximum number of referrals to follow in a
+               /// sequence during automatic referral following.
+               /// The default value is 10. A value of 0 means no limit.
+               /// The operation will be abandoned and terminated by the
+               /// API with a result code of
+               /// LdapException.REFERRAL_LIMIT_EXCEEDED if the
+               /// number of referrals in a sequence exceeds the limit.
+               /// It is ignored for asynchronous operations.
+               /// 
+               /// </param>
+               /// <seealso cref="LdapException#REFERRAL_LIMIT_EXCEEDED">
+               /// </seealso>
+               virtual public int HopLimit
+               {
+                       get
+                       {
+                               return hopLimit;
+                       }
+                       
+                       set
+                       {
+                               this.hopLimit = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Gets all the properties of the constraints object which has been
+               /// assigned with {@link #setProperty(String, Object)}.
+               /// A value of <code>null</code> is returned if no properties are defined.
+               /// 
+               /// </summary>
+               /// <seealso cref="Object)">
+               /// </seealso>
+               /// <seealso cref="LdapConnection#getProperty(String)">
+               /// </seealso>
+               /// <summary> Sets all the properties of the constraints object.
+               /// 
+               /// </summary>
+               /// <param name="props">the properties represented by the Hashtable object to set.
+               /// </param>
+               virtual internal System.Collections.Hashtable Properties
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return properties;
+                       }
+                       
+                       /* package */
+                       
+                       set
+                       {
+                               properties = (System.Collections.Hashtable) value.Clone();
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Specified whether or not referrals are followed automatically.
+               /// 
+               /// </summary>
+               /// <returns>  True if referrals are followed automatically, or
+               /// false if referrals throw an LdapReferralException.</p>
+               /// </returns>
+               /// <summary> Specifies whether referrals are followed automatically or if
+               /// referrals throw an LdapReferralException.
+               /// 
+               /// <p>Referrals of any type other than to an Ldap server (for example, a
+               /// referral URL other than ldap://something) are ignored on automatic
+               /// referral following. </p>
+               /// 
+               /// <p> The default is false.</p>
+               /// 
+               /// </summary>
+               /// <param name="doReferrals">   True to follow referrals automatically.
+               /// False to throw an LdapReferralException if
+               /// the server returns a referral.
+               /// </param>
+               virtual public bool ReferralFollowing
+               {
+                       get
+                       {
+                               return doReferrals;
+                       }
+                       
+                       set
+                       {
+                               this.doReferrals = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Returns the maximum number of milliseconds to wait for any operation
+               /// under these constraints.
+               /// 
+               /// <p>If the value is 0, there is no maximum time limit on waiting
+               /// for operation results. The actual granularity of the timeout depends
+               /// platform.  This limit is enforced the the API on an
+               /// operation, not by the server.
+               /// The operation will be abandoned and terminated by the
+               /// API with a result code of LdapException.Ldap_TIMEOUT if the
+               /// operation exceeds the time limit.</p>
+               /// 
+               /// </summary>
+               /// <returns> The maximum number of milliseconds to wait for the operation.
+               /// 
+               /// </returns>
+               /// <seealso cref="LdapException#Ldap_TIMEOUT">
+               /// </seealso>
+               /// <summary> Sets the maximum number of milliseconds the client waits for
+               /// any operation under these constraints to complete.
+               /// 
+               /// <p>If the value is 0, there is no maximum time limit enforced by the
+               /// API on waiting for the operation results. The actual granularity of
+               /// the timeout depends on the platform.
+               /// The operation will be abandoned and terminated by the
+               /// API with a result code of LdapException.Ldap_TIMEOUT if the
+               /// operation exceeds the time limit.</p>
+               /// 
+               /// </summary>
+               /// <param name="msLimit">     The maximum milliseconds to wait.
+               /// 
+               /// </param>
+               /// <seealso cref="LdapException#Ldap_TIMEOUT">
+               /// </seealso>
+               virtual public int TimeLimit
+               {
+                       get
+                       {
+                               return msLimit;
+                       }
+                       
+                       set
+                       {
+                               this.msLimit = value;
+                               return ;
+                       }
+                       
+               }
+               
+               private int msLimit = 0;
+               private int hopLimit = 10;
+               private bool doReferrals = false;
+               private LdapReferralHandler refHandler = null;
+               private LdapControl[] controls = null;
+               private static System.Object nameLock; // protect agentNum
+               private static int lConsNum = 0; // Debug, LdapConstraints num
+               private System.String name; // String name for debug
+               private System.Collections.Hashtable properties = null; // Properties
+               
+               /// <summary> Constructs a new LdapConstraints object that specifies the default
+               /// set of constraints.
+               /// </summary>
+               public LdapConstraints()
+               {
+                       // Get a unique constraints name for debug
+                       return ;
+               }
+               
+               /// <summary> Constructs a new LdapConstraints object specifying constraints that
+               /// control wait time, and referral handling.
+               /// 
+               /// </summary>
+               /// <param name="msLimit"> The maximum time in milliseconds to wait for results.
+               /// The default is 0, which means that there is no
+               /// maximum time limit. This limit is enforced for an
+               /// operation by the API, not by the server.
+               /// The operation will be abandoned and terminated by the
+               /// API with a result code of LdapException.Ldap_TIMEOUT
+               /// if the operation exceeds the time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="doReferrals">Determines whether to automatically follow
+               /// referrals or not. Specify true to follow
+               /// referrals automatically, and false to throw
+               /// an LdapReferralException if the server responds
+               /// with a referral. False is the default value.
+               /// The way referrals are followed automatically is
+               /// determined by the setting of the handler parameter.
+               /// It is ignored for asynchronous operations.
+               /// <br><br>
+               /// </param>
+               /// <param name="handler">  The custom authentication handler called when
+               /// LdapConnection needs to authenticate, typically on
+               /// following a referral.  A null may be specified to
+               /// indicate default authentication processing, i.e.
+               /// referrals are followed with anonymous authentication.
+               /// The handler object may be an implemention of either the
+               /// LdapBindHandler or LdapAuthHandler interface.
+               /// The implementation of these interfaces determines how
+               /// authentication is performed when following referrals.
+               /// It is ignored for asynchronous operations.
+               /// <br><br>
+               /// </param>
+               /// <param name="hop_limit">The maximum number of referrals to follow in a
+               /// sequence during automatic referral following.
+               /// The default value is 10. A value of 0 means no limit.
+               /// The operation will be abandoned and terminated by the
+               /// API with a result code of
+               /// LdapException.REFERRAL_LIMIT_EXCEEDED if the
+               /// number of referrals in a sequence exceeds the limit.
+               /// It is ignored for asynchronous operations.
+               /// 
+               /// </param>
+               /// <seealso cref="LdapException#Ldap_TIMEOUT">
+               /// </seealso>
+               /// <seealso cref="LdapException#REFERRAL_LIMIT_EXCEEDED">
+               /// </seealso>
+               /// <seealso cref="LdapException#REFERRAL">
+               /// </seealso>
+               /// <seealso cref="LdapReferralException">
+               /// </seealso>
+               /// <seealso cref="LdapBindHandler">
+               /// </seealso>
+               /// <seealso cref="LdapAuthHandler">
+               /// </seealso>
+               public LdapConstraints(int msLimit, bool doReferrals, LdapReferralHandler handler, int hop_limit)
+               {
+                       this.msLimit = msLimit;
+                       this.doReferrals = doReferrals;
+                       this.refHandler = handler;
+                       this.hopLimit = hop_limit;
+                       // Get a unique constraints name for debug
+                       return ;
+               }
+               
+               /// <summary> Returns the controls to be sent to the server.
+               /// 
+               /// </summary>
+               /// <returns> The controls to be sent to the server, or null if none.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setControls(LdapControl)">
+               /// </seealso>
+               /// <seealso cref="#setControls(LdapControl[])">
+               /// </seealso>
+               public virtual LdapControl[] getControls()
+               {
+                       return controls;
+               }
+               
+               /// <summary> Gets a property of the constraints object which has been
+               /// assigned with {@link #setProperty(String, Object)}.
+               /// 
+               /// </summary>
+               /// <param name="name">  Name of the property to be returned.
+               /// 
+               /// </param>
+               /// <returns> the object associated with the property,
+               /// or <code>null</code> if the property is not set.
+               /// 
+               /// </returns>
+               /// <seealso cref="Object)">
+               /// </seealso>
+               /// <seealso cref="LdapConnection#getProperty(String)">
+               /// </seealso>
+               public virtual System.Object getProperty(System.String name)
+               {
+                       if (properties == null)
+                       {
+                               return null; // Requested property not available.
+                       }
+                       return properties[name];
+               }
+               
+               /// <summary> Returns an object that can process authentication for automatic
+               /// referral handling.
+               /// 
+               /// <p>It may be null.</p>
+               /// 
+               /// </summary>
+               /// <returns> An LdapReferralHandler object that can process authentication.
+               /// </returns>
+               /*package*/
+               internal virtual LdapReferralHandler getReferralHandler()
+               {
+                       return refHandler;
+               }
+               
+               /// <summary> Sets a single control to be sent to the server.
+               /// 
+               /// </summary>
+               /// <param name="control">    A single control to be sent to the server or
+               /// null if none.
+               /// </param>
+               public virtual void  setControls(LdapControl control)
+               {
+                       if (control == null)
+                       {
+                               this.controls = null;
+                               return ;
+                       }
+                       this.controls = new LdapControl[1];
+                       this.controls[0] = (LdapControl) control.Clone();
+                       return ;
+               }
+               
+               /// <summary> Sets controls to be sent to the server.
+               /// 
+               /// </summary>
+               /// <param name="controls">     An array of controls to be sent to the server or
+               /// null if none.
+               /// </param>
+               public virtual void  setControls(LdapControl[] controls)
+               {
+                       if ((controls == null) || (controls.Length == 0))
+                       {
+                               this.controls = null;
+                               return ;
+                       }
+                       this.controls = new LdapControl[controls.Length];
+                       for (int i = 0; i < controls.Length; i++)
+                       {
+                               this.controls[i] = (LdapControl) controls[i].Clone();
+                       }
+                       return ;
+               }
+               
+               /// <summary> Sets a property of the constraints object.
+               /// 
+               /// <p>No property names have been defined at this time, but the
+               /// mechanism is in place in order to support revisional as well as
+               /// dynamic and proprietary extensions to operation modifiers.</p>
+               /// 
+               /// </summary>
+               /// <param name="name">   Name of the property to set.
+               /// <br><br>
+               /// </param>
+               /// <param name="value">  Value to assign to the property.
+               /// property is not supported.
+               /// 
+               /// @throws NullPointerException if name or value are null
+               /// 
+               /// </param>
+               /// <seealso cref=")">
+               /// </seealso>
+               /// <seealso cref="LdapConnection#getProperty(String)">
+               /// </seealso>
+               public virtual void  setProperty(System.String name, System.Object value_Renamed)
+               {
+                       if (properties == null)
+                       {
+                               properties = new System.Collections.Hashtable();
+                       }
+                       SupportClass.PutElement(properties, name, value_Renamed);
+                       return ;
+               }
+               
+               /// <summary> Specifies the object that will process authentication requests
+               /// during automatic referral following.
+               /// 
+               /// <p>The default is null.</p>
+               /// 
+               /// </summary>
+               /// <param name="handler">   An object that implements LdapBindHandler or
+               /// LdapAuthHandler
+               /// 
+               /// </param>
+               /// <seealso cref="LdapAuthHandler">
+               /// </seealso>
+               /// <seealso cref="LdapBindHandler">
+               /// </seealso>
+               public virtual void  setReferralHandler(LdapReferralHandler handler)
+               {
+                       refHandler = handler;
+                       return ;
+               }
+               
+               /// <summary> Clones an LdapConstraints object.
+               /// 
+               /// </summary>
+               /// <returns> An LdapConstraints object.
+               /// </returns>
+               public System.Object Clone()
+               {
+                       try
+                       {
+                               System.Object newObj = base.MemberwiseClone();
+                               if (controls != null)
+                               {
+                                       ((LdapConstraints) newObj).controls = new LdapControl[controls.Length];
+                                       controls.CopyTo(((LdapConstraints) newObj).controls, 0);
+                               }
+                               if (properties != null)
+                               {
+                                       ((LdapConstraints) newObj).properties = (System.Collections.Hashtable) properties.Clone();
+                               }
+                               return newObj;
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+               }
+               static LdapConstraints()
+               {
+                       nameLock = new System.Object();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapControl.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapControl.cs
new file mode 100755 (executable)
index 0000000..62dfa18
--- /dev/null
@@ -0,0 +1,237 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapControl.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Utilclass;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  Encapsulates optional additional parameters or constraints to be applied to
+       /// an Ldap operation.
+       /// 
+       /// <p>When included with LdapConstraints or LdapSearchConstraints
+       /// on an LdapConnection or with a specific operation request, it is
+       /// sent to the server along with operation requests.</p>
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#getResponseControls">
+       /// </seealso>
+       /// <seealso cref="LdapSearchConstraints#getControls">
+       /// </seealso>
+       /// <seealso cref="LdapSearchConstraints#setControls">
+       /// </seealso>
+       public class LdapControl : System.ICloneable
+       {
+               /// <summary> Returns the identifier of the control.
+               /// 
+               /// </summary>
+               /// <returns> The object ID of the control.
+               /// </returns>
+               virtual public System.String ID
+               {
+                       get
+                       {
+                               return new System.Text.StringBuilder(control.ControlType.stringValue()).ToString();
+                       }
+                       
+               }
+               /// <summary> Returns whether the control is critical for the operation.
+               /// 
+               /// </summary>
+               /// <returns> Returns true if the control must be supported for an associated
+               /// operation to be executed, and false if the control is not required for
+               /// the operation.
+               /// </returns>
+               virtual public bool Critical
+               {
+                       get
+                       {
+                               return control.Criticality.booleanValue();
+                       }
+                       
+               }
+               internal static RespControlVector RegisteredControls
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return registeredControls;
+                       }
+                       
+               }
+               /// <summary> Returns the RFC 2251 Control object.
+               /// 
+               /// </summary>
+               /// <returns> An ASN.1 RFC 2251 Control.
+               /// </returns>
+               virtual internal RfcControl Asn1Object
+               {
+                       /*package*/
+                       
+                       get
+                       {
+                               return control;
+                       }
+                       
+               }
+               
+               private static RespControlVector registeredControls;
+               
+               private RfcControl control; // An RFC 2251 Control
+               
+               /// <summary> Constructs a new LdapControl object using the specified values.
+               /// 
+               /// </summary>
+               /// <param name="oid">    The OID of the control, as a dotted string.
+               /// <br><br>
+               /// </param>
+               /// <param name="critical">  True if the Ldap operation should be discarded if
+               /// the control is not supported. False if
+               /// the operation can be processed without the control.
+               /// <br><br>
+               /// </param>
+               /// <param name="values">    The control-specific data.
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public LdapControl(System.String oid, bool critical, sbyte[] values)
+               {
+                       if ((System.Object) oid == null)
+                       {
+                               throw new System.ArgumentException("An OID must be specified");
+                       }
+                       if (values == null)
+                       {
+                               control = new RfcControl(new RfcLdapOID(oid), new Asn1Boolean(critical));
+                       }
+                       else
+                       {
+                               control = new RfcControl(new RfcLdapOID(oid), new Asn1Boolean(critical), new Asn1OctetString(values));
+                       }
+                       return ;
+               }
+               
+               /// <summary> Create an LdapControl from an existing control.</summary>
+               protected internal LdapControl(RfcControl control)
+               {
+                       this.control = control;
+                       return ;
+               }
+               
+               /// <summary> Returns a copy of the current LdapControl object.
+               /// 
+               /// </summary>
+               /// <returns> A copy of the current LdapControl object.
+               /// </returns>
+               public System.Object Clone()
+               {
+                       LdapControl cont;
+                       try
+                       {
+                               cont = (LdapControl) base.MemberwiseClone();
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+                       sbyte[] vals = this.getValue();
+                       sbyte[] twin = null;
+                       if (vals != null)
+                       {
+                               //is this necessary?
+                               // Yes even though the contructor above allocates a
+                               // new Asn1OctetString, vals in that constuctor
+                               // is only copied by reference
+                               twin = new sbyte[vals.Length];
+                               for (int i = 0; i < vals.Length; i++)
+                               {
+                                       twin[i] = vals[i];
+                               }
+                               cont.control = new RfcControl(new RfcLdapOID(ID), new Asn1Boolean(Critical), new Asn1OctetString(twin));
+                       }
+                       return cont;
+               }
+               
+               /// <summary> Returns the control-specific data of the object.
+               /// 
+               /// </summary>
+               /// <returns> The control-specific data of the object as a byte array,
+               /// or null if the control has no data.
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               public virtual sbyte[] getValue()
+               {
+                       sbyte[] result = null;
+                       Asn1OctetString val = control.ControlValue;
+                       if (val != null)
+                       {
+                               result = val.byteValue();
+                       }
+                       return result;
+               }
+               
+               
+               /// <summary> Sets the control-specific data of the object.  This method is for
+               /// use by an extension of LdapControl.
+               /// </summary>
+               [CLSCompliantAttribute(false)]
+               protected internal virtual void  setValue(sbyte[] controlValue)
+               {
+                       control.ControlValue = new Asn1OctetString(controlValue);
+                       return ;
+               }
+               
+               /// <summary> Registers a class to be instantiated on receipt of a control with the
+               /// given OID.
+               /// 
+               /// <p>Any previous registration for the OID is overridden. The
+               /// controlClass must be an extension of LdapControl.</p>
+               /// 
+               /// </summary>
+               /// <param name="oid">           The object identifier of the control.
+               /// <br><br>
+               /// </param>
+               /// <param name="controlClass">  A class which can instantiate an LdapControl.
+               /// </param>
+               public static void  register(System.String oid, System.Type controlClass)
+               {
+                       registeredControls.registerResponseControl(oid, controlClass);
+                       return ;
+               }
+               static LdapControl()
+               {
+                       registeredControls = new RespControlVector(5, 5);
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapDN.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapDN.cs
new file mode 100755 (executable)
index 0000000..ad19491
--- /dev/null
@@ -0,0 +1,262 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapDN.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using  Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  A utility class to facilitate composition and deomposition
+       /// of distinguished names (DNs).
+       /// 
+       /// <p>Specifies methods for manipulating a distinguished name (DN)
+       /// and a relative distinguished name (RDN).</p>
+       /// </summary>
+       public class LdapDN
+       {
+               /// <summary> Compares the two strings per the distinguishedNameMatch equality matching
+               /// (using case-ignore matching).  IllegalArgumentException is thrown if one
+               /// or both DNs are invalid.  UnsupportedOpersationException is thrown if the
+               /// API implementation is not able to detemine if the DNs match or not.
+               /// 
+               /// </summary>
+               /// <param name="dn1">           String form of the first DN to compare.
+               /// <br><br>
+               /// </param>
+               /// <param name="dn2">           String form of the second DN to compare.
+               /// 
+               /// </param>
+               /// <returns> Returns true if the two strings correspond to the same DN; false
+               /// if the DNs are different.
+               /// </returns>
+               [CLSCompliantAttribute(false)]          
+               public static bool equals(System.String dn1, System.String dn2)
+               {
+                       DN dnA = new DN(dn1);
+                       DN dnB = new DN(dn2);
+                       return dnA.Equals(dnB);
+               }
+               
+               /// <summary> Returns the RDN after escaping the characters requiring escaping.
+               /// 
+               /// <p>For example, for the rdn "cn=Acme, Inc", the escapeRDN method
+               /// returns "cn=Acme\, Inc".</p>
+               /// 
+               /// <p>escapeRDN escapes the AttributeValue by inserting '\' before the
+               /// following chars: * ',' '+' '"' '\' '<' '>' ';' <BR>
+               /// '#' if it comes at the beginning of the string, and <BR>
+               /// ' ' (space) if it comes at the beginning or the end of a string.
+               /// Note that single-valued attributes can be used because of ambiguity. See
+               /// RFC 2253 </p>
+               /// 
+               /// </summary>
+               /// <param name="rdn">           The RDN to escape.
+               /// 
+               /// </param>
+               /// <returns> The RDN with escaping characters.
+               /// </returns>
+               public static System.String escapeRDN(System.String rdn)
+               {
+                       System.Text.StringBuilder escapedS = new System.Text.StringBuilder(rdn);
+                       int i = 0;
+                       
+                       while (i < escapedS.Length && escapedS[i] != '=')
+                       {
+                               i++; //advance until we find the separator =
+                       }
+                       if (i == escapedS.Length)
+                       {
+                               throw new System.ArgumentException("Could not parse RDN: Attribute " + "type and name must be separated by an equal symbol, '='");
+                       }
+                       
+                       i++;
+                       //check for a space or # at the beginning of a string.
+                       if ((escapedS[i] == ' ') || (escapedS[i] == '#'))
+                       {
+                               escapedS.Insert(i++, '\\');
+                       }
+                       
+                       //loop from second char to the second to last
+                       for (; i < escapedS.Length; i++)
+                       {
+                               if ((escapedS[i] == ',') || (escapedS[i] == '+') || (escapedS[i] == '"') || (escapedS[i] == '\\') || (escapedS[i] == '<') || (escapedS[i] == '>') || (escapedS[i] == ';'))
+                               {
+                                       escapedS.Insert(i++, '\\');
+                               }
+                       }
+                       
+                       //check last char for a space
+                       if (escapedS[escapedS.Length - 1] == ' ')
+                       {
+                               escapedS.Insert(escapedS.Length - 1, '\\');
+                       }
+                       return escapedS.ToString();
+               }
+               
+               
+               
+               /// <summary> Returns the individual components of a distinguished name (DN).
+               /// 
+               /// </summary>
+               /// <param name="dn">       The distinguished name, for example, "cn=Babs
+               /// Jensen,ou=Accounting,o=Acme,c=US"
+               /// <br><br>
+               /// </param>
+               /// <param name="noTypes">  If true, returns only the values of the
+               /// components and not the names.  For example, "Babs
+               /// Jensen", "Accounting", "Acme", "US" instead of
+               /// "cn=Babs Jensen", "ou=Accounting", "o=Acme", and
+               /// "c=US".
+               /// 
+               /// </param>
+               /// <returns> An array of strings representing the individual components
+               /// of a DN, or null if the DN is not valid.
+               /// </returns>
+               public static System.String[] explodeDN(System.String dn, bool noTypes)
+               {
+                       DN dnToExplode = new DN(dn);
+                       return dnToExplode.explodeDN(noTypes);
+               }
+               
+               /// <summary> Returns the individual components of a relative distinguished name
+               /// (RDN), normalized.
+               /// 
+               /// </summary>
+               /// <param name="rdn">    The relative distinguished name, or in other words,
+               /// the left-most component of a distinguished name.
+               /// <br><br>
+               /// </param>
+               /// <param name="noTypes">  If true, returns only the values of the
+               /// components, and not the names of the component, for
+               /// example "Babs Jensen" instead of "cn=Babs Jensen".
+               /// 
+               /// </param>
+               /// <returns> An array of strings representing the individual components
+               /// of an RDN, or null if the RDN is not a valid RDN.
+               /// </returns>
+               public static System.String[] explodeRDN(System.String rdn, bool noTypes)
+               {
+                       RDN rdnToExplode = new RDN(rdn);
+                       return rdnToExplode.explodeRDN(noTypes);
+               }
+               
+               /// <summary> Returns true if the string conforms to distinguished name syntax.</summary>
+               /// <param name="dn">   String to evaluate fo distinguished name syntax.
+               /// </param>
+               /// <returns>      true if the dn is valid.
+               /// </returns>
+               public static bool isValid(System.String dn)
+               {
+                       try
+                       {
+                               new DN(dn);
+                       }
+                       catch (System.ArgumentException iae)
+                       {
+                               return false;
+                       }
+                       return true;
+               }
+               
+               /// <summary> Returns the DN normalized by removal of non-significant space characters
+               /// as per RFC 2253, section4.
+               /// 
+               /// </summary>
+               /// <returns>      a normalized string
+               /// </returns>
+               public static System.String normalize(System.String dn)
+               {
+                       DN testDN = new DN(dn);
+                       return testDN.ToString();
+               }
+               
+               
+               /// <summary> Returns the RDN after unescaping the characters requiring escaping.
+               /// 
+               /// <p>For example, for the rdn "cn=Acme\, Inc", the unescapeRDN method
+               /// returns "cn=Acme, Inc".</p>
+               /// unescapeRDN unescapes the AttributeValue by
+               /// removing the '\' when the next character fits the following:<BR>
+               /// ',' '+' '"' '\' '<' '>' ';'<BR>
+               /// '#' if it comes at the beginning of the Attribute Name
+               /// (without the '\').<BR>
+               /// ' ' (space) if it comes at the beginning or the end of the Attribute Name
+               /// </p>
+               /// </summary>
+               /// <param name="rdn">           The RDN to unescape.
+               /// 
+               /// </param>
+               /// <returns> The RDN with the escaping characters removed.
+               /// </returns>
+               public static System.String unescapeRDN(System.String rdn)
+               {
+                       System.Text.StringBuilder unescaped = new System.Text.StringBuilder();
+                       int i = 0;
+                       
+                       while (i < rdn.Length && rdn[i] != '=')
+                       {
+                               i++; //advance until we find the separator =
+                       }
+                       if (i == rdn.Length)
+                       {
+                               throw new System.ArgumentException("Could not parse rdn: Attribute " + "type and name must be separated by an equal symbol, '='");
+                       }
+                       i++;
+                       //check if the first two chars are "\ " (slash space) or "\#"
+                       if ((rdn[i] == '\\') && (i + 1 < rdn.Length - 1) && ((rdn[i + 1] == ' ') || (rdn[i + 1] == '#')))
+                       {
+                               i++;
+                       }
+                       for (; i < rdn.Length; i++)
+                       {
+                               //if the current char is a slash, not the end char, and is followed
+                               // by a special char then...
+                               if ((rdn[i] == '\\') && (i != rdn.Length - 1))
+                               {
+                                       if ((rdn[i + 1] == ',') || (rdn[i + 1] == '+') || (rdn[i + 1] == '"') || (rdn[i + 1] == '\\') || (rdn[i + 1] == '<') || (rdn[i + 1] == '>') || (rdn[i + 1] == ';'))
+                                       {
+                                               //I'm not sure if I have to check for these special chars
+                                               continue;
+                                       }
+                                       //check if the last two chars are "\ "
+                                       else if ((rdn[i + 1] == ' ') && (i + 2 == rdn.Length))
+                                       {
+                                               //if the last char is a space
+                                               continue;
+                                       }
+                               }
+                               unescaped.Append(rdn[i]);
+                       }
+                       return unescaped.ToString();
+               }
+       } //end class LdapDN
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapDeleteRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapDeleteRequest.cs
new file mode 100755 (executable)
index 0000000..f7bdd1a
--- /dev/null
@@ -0,0 +1,84 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapDeleteRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents a request to delete an entry.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso>
+   /*
+       *       DelRequest ::= [APPLICATION 10] LdapDN
+       */
+       public class LdapDeleteRequest:LdapMessage
+       {
+               /// <summary> Returns of the dn of the entry to delete from the directory
+               /// 
+               /// </summary>
+               /// <returns> the dn of the entry to delete
+               /// </returns>
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return Asn1Object.RequestDN;
+                       }
+                       
+               }
+               /// <summary> Constructs a request to delete an entry from the directory
+               /// 
+               /// </summary>
+               /// <param name="dn">the dn of the entry to delete.
+               /// 
+               /// </param>
+               /// <param name="cont">Any controls that apply to the abandon request
+               /// or null if none.
+               /// </param>
+               public LdapDeleteRequest(System.String dn, LdapControl[] cont):base(LdapMessage.DEL_REQUEST, new RfcDelRequest(dn), cont)
+               {
+                       return ;
+               }
+               
+               /// <summary> Return an Asn1 representation of this delete request
+               /// 
+               /// #return an Asn1 representation of this object
+               /// </summary>
+               public override System.String ToString()
+               {
+                       return Asn1Object.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapEntry.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapEntry.cs
new file mode 100755 (executable)
index 0000000..970e078
--- /dev/null
@@ -0,0 +1,207 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapEntry.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents a single entry in a directory, consisting of
+       /// a distinguished name (DN) and zero or more attributes.
+       /// 
+       /// <p>An instance of
+       /// LdapEntry is created in order to add an entry to a directory, and
+       /// instances of LdapEntry are returned on a search by enumerating an
+       /// LdapSearchResults.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapAttribute">
+       /// </seealso>
+       /// <seealso cref="LdapAttributeSet">
+       /// </seealso>
+       public class LdapEntry : System.IComparable
+       {
+               /// <summary> Returns the distinguished name of the entry.
+               /// 
+               /// </summary>
+               /// <returns> The distinguished name of the entry.
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return dn;
+                       }
+                       
+               }
+               protected internal System.String dn;
+               protected internal LdapAttributeSet attrs;
+               
+               /// <summary> Constructs an empty entry.</summary>
+               public LdapEntry():this(null, null)
+               {
+               }
+               
+               /// <summary> Constructs a new entry with the specified distinguished name and with
+               /// an empty attribute set.
+               /// 
+               /// </summary>
+               /// <param name="dn"> The distinguished name of the entry. The
+               /// value is not validated. An invalid distinguished
+               /// name will cause operations using this entry to fail.
+               /// 
+               /// </param>
+               public LdapEntry(System.String dn):this(dn, null)
+               {
+               }
+               
+               /// <summary> Constructs a new entry with the specified distinguished name and set
+               /// of attributes.
+               /// 
+               /// </summary>
+               /// <param name="dn">      The distinguished name of the new entry. The
+               /// value is not validated. An invalid distinguished
+               /// name will cause operations using this entry to fail.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">   The initial set of attributes assigned to the
+               /// entry.
+               /// </param>
+               public LdapEntry(System.String dn, LdapAttributeSet attrs)
+               {
+                       if ((System.Object) dn == null)
+                       {
+                               dn = "";
+                       }
+                       if (attrs == null)
+                       {
+                               attrs = new LdapAttributeSet();
+                       }
+                       this.dn = dn;
+                       this.attrs = attrs;
+                       return ;
+               }
+               
+               /// <summary> Returns the attributes matching the specified attrName.
+               /// 
+               /// </summary>
+               /// <param name="attrName">The name of the attribute or attributes to return.
+               /// <br><br>
+               /// </param>
+               /// <returns> An array of LdapAttribute objects.
+               /// </returns>
+               public virtual LdapAttribute getAttribute(System.String attrName)
+               {
+                       return attrs.getAttribute(attrName);
+               }
+               
+               /// <summary> Returns the attribute set of the entry.
+               /// 
+               /// <p>All base and subtype variants of all attributes are
+               /// returned. The LdapAttributeSet returned may be
+               /// empty if there are no attributes in the entry. </p>
+               /// 
+               /// </summary>
+               /// <returns> The attribute set of the entry.
+               /// </returns>
+               public virtual LdapAttributeSet getAttributeSet()
+               {
+                       return attrs;
+               }
+               
+               
+               /// <summary> Returns an attribute set from the entry, consisting of only those
+               /// attributes matching the specified subtypes.
+               /// 
+               /// <p>The getAttributeSet method can be used to extract only
+               /// a particular language variant subtype of each attribute,
+               /// if it exists. The "subtype" may be, for example, "lang-ja", "binary",
+               /// or "lang-ja;phonetic". If more than one subtype is specified, separated
+               /// with a semicolon, only those attributes with all of the named
+               /// subtypes will be returned. The LdapAttributeSet returned may be
+               /// empty if there are no matching attributes in the entry. </p>
+               /// 
+               /// </summary>
+               /// <param name="subtype"> One or more subtype specification(s), separated
+               /// with semicolons. The "lang-ja" and
+               /// "lang-en;phonetic" are valid subtype
+               /// specifications.
+               /// 
+               /// </param>
+               /// <returns> An attribute set from the entry with the attributes that
+               /// match the specified subtypes or an empty set if no attributes
+               /// match.
+               /// </returns>
+               public virtual LdapAttributeSet getAttributeSet(System.String subtype)
+               {
+                       return attrs.getSubset(subtype);
+               }
+               
+               /// <summary> Compares this object with the specified object for order.
+               /// 
+               /// <p>Ordering is determined by comparing normalized DN values
+               /// (see {@link LdapEntry#getDN() } and
+               /// {@link LdapDN#normalize(java.lang.String)}) using the
+               /// compareTo method of the String class.  </p>
+               /// 
+               /// </summary>
+               /// <param name="entry">    Entry to compare to
+               /// 
+               /// </param>
+               /// <returns>          A negative integer, zero, or a positive integer as this
+               /// object is less than, equal to, or greater than the specified object.
+               /// </returns>
+               public virtual int CompareTo(System.Object entry)
+               {
+                       return LdapDN.normalize(this.dn).CompareTo(LdapDN.normalize(((LdapEntry) entry).dn));
+               }
+               
+               /// <summary> Returns a string representation of this LdapEntry
+               /// 
+               /// </summary>
+               /// <returns> a string representation of this LdapEntry
+               /// </returns>
+               public override System.String ToString()
+               {
+                       System.Text.StringBuilder result = new System.Text.StringBuilder("LdapEntry: ");
+                       if ((System.Object) dn != null)
+                       {
+                               result.Append(dn + "; ");
+                       }
+                       if (attrs != null)
+                       {
+                               result.Append(attrs.ToString());
+                       }
+                       return result.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapException.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapException.cs
new file mode 100755 (executable)
index 0000000..37d346c
--- /dev/null
@@ -0,0 +1,1142 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapException.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  Thrown to indicate that an Ldap exception has occurred. This is a general
+       /// exception which includes a message and an Ldap result code.
+       /// 
+       /// <p>An LdapException can result from physical problems (such as
+       /// network errors) as well as problems with Ldap operations detected
+       /// by the server. For example, if an Ldap add operation fails because of a
+       /// duplicate entry, the server returns a result code.</p>
+       /// 
+       /// <p>Five possible sources of information are available from LdapException:
+       /// <dl>
+       /// <dt>Result Code:</dt>
+       /// <dd>The <code>getResultCode</code> method returns a result code,
+       /// which can be compared against standard Ldap result codes. </dd>
+       /// <dt>Message:</dt>
+       /// <dd>The <code>getMessage</code> method returns a localized message
+       /// from the message resource that corresponds to the result code.
+       /// </dd>
+       /// <dt>Ldap server Message:</dt>
+       /// <dd>The <code>getLdapErrorMessage</code> method returns any error
+       /// message received from the Ldap server.</dd>
+       /// <dt>Matched DN:</dt>
+       /// <dd>The <code>getMatchedDN</code> method retrieves the part of a
+       /// submitted distinguished name which could be matched by the server</dd>
+       /// <dt>Root Cause:</dt>
+       /// <dd>The <code>getCause</code> method returns the a nested exception
+       /// that was the original cause for the error. </dd>
+       /// </dl></p>
+       /// 
+       /// <p>The <code>toString</code> method returns a string containing all
+       /// the above sources of information, if they have a value.</p>
+       /// 
+       /// <p>Exceptions generated by the API, i.e. that are not a result
+       /// of a server response, can be identified as <tt>instanceof
+       /// {@link LdapLocalException}</tt>
+       /// 
+       /// <p>The following table lists the standard Ldap result codes.
+       /// See RFC2251 for a discussion of the meanings of the result codes.
+       /// The corresponding ASN.1 definition from RFC2251 is provided in parentheses.</p>
+       /// <table>
+       /// <tr>
+       /// <td><b>Value</b>
+       /// <td><b>Result Code</b>
+       /// </tr>
+       /// <tr><td> 0</td><td>{@link #SUCCESS} (success) </td></tr>
+       /// <tr><td> 1</td><td>{@link #OPERATIONS_ERROR} (operationsError) </td></tr>
+       /// <tr><td> 2</td><td>{@link #PROTOCOL_ERROR} (protocolError) </td></tr>
+       /// <tr><td> 3</td><td>{@link #TIME_LIMIT_EXCEEDED} (timeLimitExceeded) </td></tr>
+       /// <tr><td> 4</td><td>{@link #SIZE_LIMIT_EXCEEDED} (sizeLimitExceeded) </td></tr>
+       /// <tr><td> 5</td><td>{@link #COMPARE_FALSE} (compareFalse) </td></tr>
+       /// <tr><td> 6</td><td>{@link #COMPARE_TRUE} (compareTrue) </td></tr>
+       /// <tr><td> 7</td><td>{@link #AUTH_METHOD_NOT_SUPPORTED} (authMethodNotSupported) </td></tr>
+       /// <tr><td> 8</td><td>{@link #STRONG_AUTH_REQUIRED} (strongAuthRequired) </td></tr>
+       /// <tr><td> 10</td><td>{@link #REFERRAL} (referral) </td></tr>
+       /// <tr><td> 11</td><td>{@link #ADMIN_LIMIT_EXCEEDED} (adminLimitExceeded) </td></tr>
+       /// <tr><td> 12</td><td>{@link #UNAVAILABLE_CRITICAL_EXTENSION} (unavailableCriticalExtension) </td></tr>
+       /// <tr><td> 13</td><td>{@link #CONFIDENTIALITY_REQUIRED} (confidentialityRequired) </td></tr>
+       /// <tr><td> 14</td><td>{@link #SASL_BIND_IN_PROGRESS} (saslBindInProgress) </td></tr>
+       /// <tr><td> 16</td><td>{@link #NO_SUCH_ATTRIBUTE} (noSuchAttribute) </td></tr>
+       /// <tr><td> 17</td><td>{@link #UNDEFINED_ATTRIBUTE_TYPE} (undefinedAttributeType) </td></tr>
+       /// <tr><td> 18</td><td>{@link #INAPPROPRIATE_MATCHING} (inappropriateMatching) </td></tr>
+       /// <tr><td> 19</td><td>{@link #CONSTRAINT_VIOLATION} (constraintViolation) </td></tr>
+       /// <tr><td> 20</td><td>{@link #ATTRIBUTE_OR_VALUE_EXISTS} (AttributeOrValueExists) </td></tr>
+       /// <tr><td> 21</td><td>{@link #INVALID_ATTRIBUTE_SYNTAX} (invalidAttributeSyntax) </td></tr>
+       /// <tr><td> 32</td><td>{@link #NO_SUCH_OBJECT} (noSuchObject) </td></tr>
+       /// <tr><td> 33</td><td>{@link #ALIAS_PROBLEM} (aliasProblem) </td></tr>
+       /// <tr><td> 34</td><td>{@link #INVALID_DN_SYNTAX} (invalidDNSyntax) </td></tr>
+       /// <tr><td> 35</td><td>{@link #IS_LEAF} (isLeaf) </td></tr>
+       /// <tr><td> 36</td><td>{@link #ALIAS_DEREFERENCING_PROBLEM} (aliasDereferencingProblem) </td></tr>
+       /// <tr><td> 48</td><td>{@link #INAPPROPRIATE_AUTHENTICATION} (inappropriateAuthentication) </td></tr>
+       /// <tr><td> 49</td><td>{@link #INVALID_CREDENTIALS} (invalidCredentials) </td></tr>
+       /// <tr><td> 50</td><td>{@link #INSUFFICIENT_ACCESS_RIGHTS} (insufficientAccessRights) </td></tr>
+       /// <tr><td> 51</td><td>{@link #BUSY} (busy) </td></tr>
+       /// <tr><td> 52</td><td>{@link #UNAVAILABLE} (unavailable) </td></tr>
+       /// <tr><td> 53</td><td>{@link #UNWILLING_TO_PERFORM} (unwillingToPerform) </td></tr>
+       /// <tr><td> 54</td><td>{@link #LOOP_DETECT} (loopDetect) </td></tr>
+       /// <tr><td> 64</td><td>{@link #NAMING_VIOLATION} (namingViolation) </td></tr>
+       /// <tr><td> 65</td><td>{@link #OBJECT_CLASS_VIOLATION} (objectClassViolation) </td></tr>
+       /// <tr><td> 66</td><td>{@link #NOT_ALLOWED_ON_NONLEAF} (notAllowedOnNonLeaf) </td></tr>
+       /// <tr><td> 67</td><td>{@link #NOT_ALLOWED_ON_RDN} (notAllowedOnRDN) </td></tr>
+       /// <tr><td> 68</td><td>{@link #ENTRY_ALREADY_EXISTS} (entryAlreadyExists) </td></tr>
+       /// <tr><td> 69</td><td>{@link #OBJECT_CLASS_MODS_PROHIBITED} (objectClassModsProhibited) </td></tr>
+       /// <tr><td> 71</td><td>{@link #AFFECTS_MULTIPLE_DSAS} (affectsMultipleDSAs </td></tr>
+       /// <tr><td> 80</td><td>{@link #OTHER} (other) </td></tr>
+       /// </table>
+       /// 
+       /// <p>Local errors, resulting from actions other than an operation on a
+       /// server.</p>
+       /// 
+       /// <table>
+       /// <tr>
+       /// <td><b>Value</b>
+       /// <td><b>Result Code</b>
+       /// </tr>
+       /// <tr><td>81</td><td>{@link #SERVER_DOWN}</td></tr>
+       /// <tr><td>82</td><td>{@link #LOCAL_ERROR}</td></tr>
+       /// <tr><td>83</td><td>{@link #ENCODING_ERROR}</td></tr>
+       /// <tr><td>84</td><td>{@link #DECODING_ERROR}</td></tr>
+       /// <tr><td>85</td><td>{@link #Ldap_TIMEOUT}</td></tr>
+       /// <tr><td>86</td><td>{@link #AUTH_UNKNOWN}</td></tr>
+       /// <tr><td>87</td><td>{@link #FILTER_ERROR}</td></tr>
+       /// <tr><td>88</td><td>{@link #USER_CANCELLED}</td></tr>
+       /// <tr><td>90</td><td>{@link #NO_MEMORY}</td></tr>
+       /// <tr><td>91</td><td>{@link #CONNECT_ERROR}</td></tr>
+       /// <tr><td>92</td><td>{@link #Ldap_NOT_SUPPORTED}</td></tr>
+       /// <tr><td>93</td><td>{@link #CONTROL_NOT_FOUND}</td></tr>
+       /// <tr><td>94</td><td>{@link #NO_RESULTS_RETURNED}</td></tr>
+       /// <tr><td>95</td><td>{@link #MORE_RESULTS_TO_RETURN}</td></tr>
+       /// <tr><td>96</td><td>{@link #CLIENT_LOOP}</td></tr>
+       /// <tr><td>97</td><td>{@link #REFERRAL_LIMIT_EXCEEDED}</td></tr>
+       /// <tr><td>100</td><td>{@link #INVALID_RESPONSE}</td></tr>
+       /// <tr><td>101</td><td>{@link #AMBIGUOUS_RESPONSE}</td></tr>
+       /// <tr><td>112</td><td>{@link #TLS_NOT_SUPPORTED}</td></tr>
+       /// </table>
+       /// </summary>
+       
+       public class LdapException:System.Exception
+       {
+               /// <summary> Returns the error message from the Ldap server, if this message is
+               /// available (that is, if this message was set). If the message was not set,
+               /// this method returns null.
+               /// 
+               /// </summary>
+               /// <returns> The error message or null if the message was not set.
+               /// 
+               /// </returns>
+               virtual public System.String LdapErrorMessage
+               {
+                       get
+                       {
+                               if (((System.Object) serverMessage != null) && (serverMessage.Length == 0))
+                               {
+                                       return null;
+                               }
+                               return serverMessage;
+                       }
+                       
+               }
+               /// <summary> Returns the lower level Exception which caused the failure, if any.
+               /// For example, an IOException with additional information may be returned
+               /// on a CONNECT_ERROR failure.
+               /// </summary>
+               virtual public System.Exception Cause
+               {
+                       get
+                       {
+                               return rootException;
+                       }
+                       
+               }
+               /// <summary> Returns the result code from the exception.
+               /// 
+               /// <p>The codes are defined as <code>public final static int</code> members
+               /// of the Ldap Exception class. If the exception is a
+               /// result of error information returned from a directory operation, the
+               /// code will be one of those defined for the class. Otherwise, a local error
+               /// code is returned. </p>
+               /// </summary>
+               virtual public int ResultCode
+               {
+                       get
+                       {
+                               return resultCode;
+                       }
+                       
+               }
+               /// <summary> Returns the part of a submitted distinguished name which could be
+               /// matched by the server.
+               /// 
+               /// </p>If the exception was caused by a local error, such as no server
+               /// available, the return value is null. If the exception resulted from
+               /// an operation being executed on a server, the value is an empty string
+               /// except when the result of the operation was one of the following:</p>
+               /// <ul>
+               /// <li>NO_SUCH_OBJECT</li>
+               /// <li>ALIAS_PROBLEM</li>
+               /// <li>INVALID_DN_SYNTAX</li>
+               /// <li>ALIAS_DEREFERENCING_PROBLEM</li>
+               /// </ul>
+               /// 
+               /// </summary>
+               /// <returns> The part of a submitted distinguished name which could be
+               /// matched by the server or null if the error is a local error.
+               /// </returns>
+               virtual public System.String MatchedDN
+               {
+                       get
+                       {
+                               return matchedDN;
+                       }
+                       
+               }
+               public override System.String Message
+               {
+                       get
+                       {
+                               return resultCodeToString();
+                       }
+                       
+               }
+       /*      public override System.String Message
+               {
+                       get
+                       {
+                               return resultCodeToString();
+                       }
+                       
+               }
+    */         
+               // The Result Code
+               private int resultCode = 0;
+               // The localized message
+               private System.String messageOrKey = null;
+               // The arguments associated with the localized message
+               private System.Object[] arguments = null;
+               // The Matched DN
+               private System.String matchedDN = null;
+               // The Root Cause
+               private System.Exception rootException = null;
+               // A message from the server
+               private System.String serverMessage = null;
+               
+               /// <summary>Indicates the requested client operation completed successfully.
+               /// 
+               /// <p>SUCCESS = 0<p/>
+               /// </summary>
+               public const int SUCCESS = 0;
+               
+               /// <summary> Indicates an internal error.
+               /// 
+               /// <p>The server is unable to respond with a more specific error and is
+               /// also unable to properly respond to a request. It does not indicate
+               /// that the client has sent an erroneous message.</p>
+               /// 
+               /// <p>OPERATIONS_ERROR = 1</p>
+               /// </summary>
+               public const int OPERATIONS_ERROR = 1;
+               
+               /// <summary> Indicates that the server has received an invalid or malformed request
+               /// from the client.
+               /// 
+               /// <p>PROTOCOL_ERROR = 2</p>
+               /// </summary>
+               public const int PROTOCOL_ERROR = 2;
+               
+               /// <summary> Indicates that the operation's time limit specified by either the
+               /// client or the server has been exceeded.
+               /// 
+               /// <p>On search operations, incomplete results are returned.</p>
+               /// 
+               /// <p>TIME_LIMIT_EXCEEDED = 3</p>
+               /// </summary>
+               public const int TIME_LIMIT_EXCEEDED = 3;
+               
+               /// <summary> Indicates that in a search operation, the size limit specified by
+               /// the client or the server has been exceeded. Incomplete results are
+               /// returned.
+               /// 
+               /// <p>SIZE_LIMIT_EXCEEDED = 4</p>
+               /// </summary>
+               public const int SIZE_LIMIT_EXCEEDED = 4;
+               
+               /// <summary> Does not indicate an error condition. Indicates that the results of
+               /// a compare operation are false.
+               /// 
+               /// <p>COMPARE_FALSE = 5</p>
+               /// </summary>
+               public const int COMPARE_FALSE = 5;
+               
+               /// <summary> Does not indicate an error condition. Indicates that the results of a
+               /// compare operation are true.
+               /// 
+               /// <p>COMPARE_TRUE = 6</p>
+               /// </summary>
+               public const int COMPARE_TRUE = 6;
+               
+               /// <summary> Indicates that during a bind operation the client requested an
+               /// authentication method not supported by the Ldap server.
+               /// 
+               /// <p>AUTH_METHOD_NOT_SUPPORTED = 7</p>
+               /// </summary>
+               public const int AUTH_METHOD_NOT_SUPPORTED = 7;
+               
+               /// <summary>Indicates a problem with the level of authentication.
+               /// 
+               /// <p>One of the following has occurred:
+               /// <ul>
+               /// <li>In bind requests, the Ldap server accepts only strong
+               /// authentication.</li>
+               /// <li>In a client request, the client requested an operation such as delete
+               /// that requires strong authentication.</li>
+               /// <li>In an unsolicited notice of disconnection, the Ldap server discovers
+               /// the security protecting the communication between the client and
+               /// server has unexpectedly failed or been compromised.</li>
+               /// </ul>
+               /// <p>STRONG_AUTH_REQUIRED = 8</p>
+               /// </summary>
+               public const int STRONG_AUTH_REQUIRED = 8;
+               
+               /// <summary> Returned by some Ldap servers to Ldapv2 clients to indicate that a referral
+               /// has been returned in the error string.
+               /// 
+               /// <p>Ldap_PARTIAL_RESULTS = 9</p>
+               /// </summary>
+               public const int Ldap_PARTIAL_RESULTS = 9;
+               
+               /// <summary> Does not indicate an error condition. In Ldapv3, indicates that the server
+               /// does not hold the target entry of the request, but that the servers in the
+               /// referral field may.
+               /// 
+               /// <p>REFERRAL = 10</p>
+               /// </summary>
+               public const int REFERRAL = 10;
+               
+               /// <summary> Indicates that an Ldap server limit set by an administrative authority
+               /// has been exceeded.
+               /// 
+               /// <p>ADMIN_LIMIT_EXCEEDED = 11</p>
+               /// </summary>
+               public const int ADMIN_LIMIT_EXCEEDED = 11;
+               
+               /// <summary> Indicates that the Ldap server was unable to satisfy a request because
+               /// one or more critical extensions were not available.
+               /// 
+               /// <p>Either the server does not support the control or the control is not
+               /// appropriate for the operation type.</p>
+               /// 
+               /// <p>UNAVAILABLE_CRITICAL_EXTENSION = 12</p>
+               /// </summary>
+               public const int UNAVAILABLE_CRITICAL_EXTENSION = 12;
+               
+               /// <summary> Indicates that the session is not protected by a protocol such as
+               /// Transport Layer Security (TLS), which provides session confidentiality.
+               /// 
+               /// <p>CONFIDENTIALITY_REQUIRED = 13</p>
+               /// </summary>
+               public const int CONFIDENTIALITY_REQUIRED = 13;
+               
+               /// <summary> Does not indicate an error condition, but indicates that the server is
+               /// ready for the next step in the process. The client must send the server
+               /// the same SASL mechanism to continue the process.
+               /// 
+               /// <p>SASL_BIND_IN_PROGRESS = 14</p>
+               /// </summary>
+               public const int SASL_BIND_IN_PROGRESS = 14;
+               
+               /// <summary> Indicates that the attribute specified in the modify or compare
+               /// operation does not exist in the entry.
+               /// 
+               /// <p>NO_SUCH_ATTRIBUTE = 16</p>
+               /// </summary>
+               public const int NO_SUCH_ATTRIBUTE = 16;
+               
+               /// <summary> Indicates that the attribute specified in the modify or add operation
+               /// does not exist in the Ldap server's schema.
+               /// 
+               /// <p>UNDEFINED_ATTRIBUTE_TYPE = 17</p>
+               /// </summary>
+               public const int UNDEFINED_ATTRIBUTE_TYPE = 17;
+               
+               /// <summary> Indicates that the matching rule specified in the search filter does
+               /// not match a rule defined for the attribute's syntax.
+               /// 
+               /// <p>INAPPROPRIATE_MATCHING = 18</p>
+               /// </summary>
+               public const int INAPPROPRIATE_MATCHING = 18;
+               
+               /// <summary> Indicates that the attribute value specified in a modify, add, or
+               /// modify DN operation violates constraints placed on the attribute. The
+               /// constraint can be one of size or content (for example, string only,
+               /// no binary data).
+               /// 
+               /// <p>CONSTRAINT_VIOLATION = 19</p>
+               /// </summary>
+               public const int CONSTRAINT_VIOLATION = 19;
+               
+               /// <summary> Indicates that the attribute value specified in a modify or add
+               /// operation already exists as a value for that attribute.
+               /// 
+               /// <p>ATTRIBUTE_OR_VALUE_EXISTS = 20</p>
+               /// </summary>
+               public const int ATTRIBUTE_OR_VALUE_EXISTS = 20;
+               
+               /// <summary> Indicates that the attribute value specified in an add, compare, or
+               /// modify operation is an unrecognized or invalid syntax for the attribute.
+               /// 
+               /// <p>INVALID_ATTRIBUTE_SYNTAX = 21</p>
+               /// </summary>
+               public const int INVALID_ATTRIBUTE_SYNTAX = 21;
+               
+               /// <summary> Indicates the target object cannot be found.
+               /// 
+               /// <p>This code is not returned on the following operations:</p>
+               /// <ul>
+               /// <li>Search operations that find the search base but cannot find any
+               /// entries that match the search filter.</li>
+               /// <li>Bind operations.</li>
+               /// </ul>
+               /// <p>NO_SUCH_OBJECT = 32</p>
+               /// </summary>
+               public const int NO_SUCH_OBJECT = 32;
+               
+               /// <summary> Indicates that an error occurred when an alias was dereferenced.
+               /// 
+               /// <p>ALIAS_PROBLEM = 33</p>
+               /// </summary>
+               public const int ALIAS_PROBLEM = 33;
+               
+               /// <summary> Indicates that the syntax of the DN is incorrect.
+               /// 
+               /// <p>If the DN syntax is correct, but the Ldap server's structure
+               /// rules do not permit the operation, the server returns
+               /// Ldap_UNWILLING_TO_PERFORM. </p>
+               /// 
+               /// <p>INVALID_DN_SYNTAX = 34</p>
+               /// </summary>
+               public const int INVALID_DN_SYNTAX = 34;
+               
+               /// <summary> Indicates that the specified operation cannot be performed on a
+               /// leaf entry.
+               /// 
+               /// <p>This code is not currently in the Ldap specifications, but is
+               /// reserved for this constant.</p>
+               /// 
+               /// <p>IS_LEAF = 35</p>
+               /// </summary>
+               public const int IS_LEAF = 35;
+               
+               /// <summary> Indicates that during a search operation, either the client does not
+               /// have access rights to read the aliased object's name or dereferencing
+               /// is not allowed.
+               /// 
+               /// <p>ALIAS_DEREFERENCING_PROBLEM = 36</p>
+               /// </summary>
+               public const int ALIAS_DEREFERENCING_PROBLEM = 36;
+               
+               /// <summary> Indicates that during a bind operation, the client is attempting to use
+               /// an authentication method that the client cannot use correctly.
+               /// 
+               /// <p> For example, either of the following cause this error:</p>
+               /// <ul>
+               /// <li>The client returns simple credentials when strong credentials are
+               /// required.
+               /// <li>The client returns a DN and a password for a simple bind when the
+               /// entry does not have a password defined.
+               /// </ul>
+               /// <p>INAPPROPRIATE_AUTHENTICATION = 48</p>
+               /// </summary>
+               public const int INAPPROPRIATE_AUTHENTICATION = 48;
+               
+               /// <summary> Indicates that invalid information was passed during a bind operation.
+               /// 
+               /// <p>One of the following occurred:
+               /// <ul>
+               /// <li> The client passed either an incorrect DN or password.</li>
+               /// <li> The password is incorrect because it has expired, intruder detection
+               /// has locked the account, or some other similar reason.</li>
+               /// </ul>
+               /// <p>INVALID_CREDENTIALS = 49</p>
+               /// </summary>
+               public const int INVALID_CREDENTIALS = 49;
+               
+               /// <summary> Indicates that the caller does not have sufficient rights to perform
+               /// the requested operation.
+               /// 
+               /// <p>INSUFFICIENT_ACCESS_RIGHTS = 50</p>
+               /// </summary>
+               public const int INSUFFICIENT_ACCESS_RIGHTS = 50;
+               
+               /// <summary> Indicates that the Ldap server is too busy to process the client request
+               /// at this time, but if the client waits and resubmits the request, the
+               /// server may be able to process it then.
+               /// 
+               /// <p>BUSY = 51</p>
+               /// </summary>
+               public const int BUSY = 51;
+               
+               /// <summary> Indicates that the Ldap server cannot process the client's bind
+               /// request, usually because it is shutting down.
+               /// 
+               /// <p>UNAVAILABLE = 52</p>
+               /// </summary>
+               public const int UNAVAILABLE = 52;
+               
+               /// <summary> Indicates that the Ldap server cannot process the request because of
+               /// server-defined restrictions.
+               /// 
+               /// <p>This error is returned for the following reasons:</p>
+               /// <ul>
+               /// <li>The add entry request violates the server's structure rules.</li>
+               /// <li>The modify attribute request specifies attributes that users
+               /// cannot modify.</li>
+               /// </ul>
+               /// <p>UNWILLING_TO_PERFORM = 53</p>
+               /// </summary>
+               public const int UNWILLING_TO_PERFORM = 53;
+               
+               /// <summary> Indicates that the client discovered an alias or referral loop,
+               /// and is thus unable to complete this request.
+               /// 
+               /// <p>LOOP_DETECT = 54</p>
+               /// </summary>
+               public const int LOOP_DETECT = 54;
+               
+               /// <summary> Indicates that the add or modify DN operation violates the schema's
+               /// structure rules.
+               /// 
+               /// <p>For example,</p>
+               /// <ul>
+               /// <li>The request places the entry subordinate to an alias.</li>
+               /// <li>The request places the entry subordinate to a container that
+               /// is forbidden by the containment rules.</li>
+               /// <li>The RDN for the entry uses a forbidden attribute type.</li>
+               /// 
+               /// <p>NAMING_VIOLATION = 64</p>
+               /// </summary>
+               public const int NAMING_VIOLATION = 64;
+               
+               /// <summary> Indicates that the add, modify, or modify DN operation violates the
+               /// object class rules for the entry.
+               /// 
+               /// <p>For example, the following types of request return this error:</p>
+               /// <ul>
+               /// <li>The add or modify operation tries to add an entry without a value
+               /// for a required attribute.</li>
+               /// <li>The add or modify operation tries to add an entry with a value for
+               /// an attribute which the class definition does not contain.</li>
+               /// <li>The modify operation tries to remove a required attribute without
+               /// removing the auxiliary class that defines the attribute as required.</li>
+               /// </ul>
+               /// <p>OBJECT_CLASS_VIOLATION = 65</p>
+               /// </summary>
+               public const int OBJECT_CLASS_VIOLATION = 65;
+               
+               /// <summary> Indicates that the requested operation is permitted only on leaf entries.
+               /// 
+               /// <p>For example, the following types of requests return this error:</p>
+               /// <ul>
+               /// <li>The client requests a delete operation on a parent entry.</li>
+               /// <li> The client request a modify DN operation on a parent entry.</li>
+               /// </ul>
+               /// <p>NOT_ALLOWED_ON_NONLEAF = 66</p>
+               /// </summary>
+               public const int NOT_ALLOWED_ON_NONLEAF = 66;
+               
+               /// <summary> Indicates that the modify operation attempted to remove an attribute
+               /// value that forms the entry's relative distinguished name.
+               /// 
+               /// <p>NOT_ALLOWED_ON_RDN = 67</p>
+               /// </summary>
+               public const int NOT_ALLOWED_ON_RDN = 67;
+               
+               /// <summary> Indicates that the add operation attempted to add an entry that already
+               /// exists, or that the modify operation attempted to rename an entry to the
+               /// name of an entry that already exists.
+               /// 
+               /// <p>ENTRY_ALREADY_EXISTS = 68</p>
+               /// </summary>
+               public const int ENTRY_ALREADY_EXISTS = 68;
+               
+               /// <summary> Indicates that the modify operation attempted to modify the structure
+               /// rules of an object class.
+               /// 
+               /// <p>OBJECT_CLASS_MODS_PROHIBITED = 69</p>
+               /// </summary>
+               public const int OBJECT_CLASS_MODS_PROHIBITED = 69;
+               
+               /// <summary> Indicates that the modify DN operation moves the entry from one Ldap
+               /// server to another and thus requires more than one Ldap server.
+               /// 
+               /// <p>AFFECTS_MULTIPLE_DSAS = 71</p>
+               /// </summary>
+               public const int AFFECTS_MULTIPLE_DSAS = 71;
+               
+               /// <summary> Indicates an unknown error condition.
+               /// 
+               /// <p>OTHER = 80</p>
+               /// </summary>
+               public const int OTHER = 80;
+               
+               /////////////////////////////////////////////////////////////////////////////
+               // Local Errors, resulting from actions other than an operation on a server
+               /////////////////////////////////////////////////////////////////////////////
+               
+               /// <summary> Indicates that the Ldap libraries cannot establish an initial connection
+               /// with the Ldap server. Either the Ldap server is down or the specified
+               /// host name or port number is incorrect.
+               /// 
+               /// <p>SERVER_DOWN = 81</p>
+               /// </summary>
+               public const int SERVER_DOWN = 81;
+               
+               /// <summary> Indicates that the Ldap client has an error. This is usually a failed
+               /// dynamic memory allocation error.
+               /// 
+               /// <p>LOCAL_ERROR = 82</p>
+               /// </summary>
+               public const int LOCAL_ERROR = 82;
+               
+               /// <summary> Indicates that the Ldap client encountered errors when encoding an
+               /// Ldap request intended for the Ldap server.
+               /// 
+               /// <p>ENCODING_ERROR = 83</p>
+               /// </summary>
+               public const int ENCODING_ERROR = 83;
+               
+               /// <summary> Indicates that the Ldap client encountered errors when decoding an
+               /// Ldap response from the Ldap server.
+               /// 
+               /// <p>DECODING_ERROR = 84</p>
+               /// </summary>
+               public const int DECODING_ERROR = 84;
+               
+               /// <summary> Indicates that the time limit of the Ldap client was exceeded while
+               /// waiting for a result.
+               /// 
+               /// <p>Ldap_TIMEOUT = 85</p>
+               /// </summary>
+               public const int Ldap_TIMEOUT = 85;
+               
+               /// <summary> Indicates that a bind method was called with an unknown
+               /// authentication method.
+               /// 
+               /// <p>AUTH_UNKNOWN = 86</p>
+               /// </summary>
+               public const int AUTH_UNKNOWN = 86;
+               
+               /// <summary> Indicates that the search method was called with an invalid
+               /// search filter.
+               /// 
+               /// <p>FILTER_ERROR = 87</p>
+               /// </summary>
+               public const int FILTER_ERROR = 87;
+               
+               /// <summary> Indicates that the user cancelled the Ldap operation.
+               /// 
+               /// <p>USER_CANCELLED = 88</p>
+               /// </summary>
+               public const int USER_CANCELLED = 88;
+               
+               
+               /// <summary> Indicates that a dynamic memory allocation method failed when calling
+               /// an Ldap method.
+               /// 
+               /// <p>NO_MEMORY = 90</p>
+               /// </summary>
+               public const int NO_MEMORY = 90;
+               
+               /// <summary> Indicates that the Ldap client has lost either its connection or
+               /// cannot establish a connection to the Ldap server.
+               /// 
+               /// <p>CONNECT_ERROR = 91</p>
+               /// </summary>
+               public const int CONNECT_ERROR = 91;
+               
+               /// <summary> Indicates that the requested functionality is not supported by the
+               /// client. For example, if the Ldap client is established as an Ldapv2
+               /// client, the libraries set this error code when the client requests
+               /// Ldapv3 functionality.
+               /// 
+               /// <p>Ldap_NOT_SUPPORTED = 92</p>
+               /// </summary>
+               public const int Ldap_NOT_SUPPORTED = 92;
+               
+               /// <summary> Indicates that the client requested a control that the libraries
+               /// cannot find in the list of supported controls sent by the Ldap server.
+               /// 
+               /// <p>CONTROL_NOT_FOUND = 93</p>
+               /// </summary>
+               public const int CONTROL_NOT_FOUND = 93;
+               
+               /// <summary> Indicates that the Ldap server sent no results.
+               /// 
+               /// <p>NO_RESULTS_RETURNED = 94</p>
+               /// </summary>
+               public const int NO_RESULTS_RETURNED = 94;
+               
+               /// <summary> Indicates that more results are chained in the result message.
+               /// 
+               /// <p>MORE_RESULTS_TO_RETURN = 95</p>
+               /// </summary>
+               public const int MORE_RESULTS_TO_RETURN = 95;
+               
+               /// <summary> Indicates the Ldap libraries detected a loop. Usually this happens
+               /// when following referrals.
+               /// 
+               /// <p>CLIENT_LOOP = 96</p>
+               /// </summary>
+               public const int CLIENT_LOOP = 96;
+               
+               /// <summary> Indicates that the referral exceeds the hop limit. The default hop
+               /// limit is ten.
+               /// 
+               /// <p>The hop limit determines how many servers the client can hop through
+               /// to retrieve data. For example, suppose the following conditions:</p>
+               /// <ul>
+               /// <li>Suppose the hop limit is two.</li>
+               /// <li> If the referral is to server D which can be contacted only through
+               /// server B (1 hop) which contacts server C (2 hops) which contacts
+               /// server D (3 hops).</li>
+               /// </ul>
+               /// <p> With these conditions, the hop limit is exceeded and the Ldap
+               /// libraries set this code.</p>
+               /// 
+               /// <p>REFERRAL_LIMIT_EXCEEDED = 97</p>
+               /// </summary>
+               public const int REFERRAL_LIMIT_EXCEEDED = 97;
+               
+               /// <summary> Indicates that the server response to a request is invalid.
+               /// 
+               /// <p>INVALID_RESPONSE = 100</p>
+               /// </summary>
+               public const int INVALID_RESPONSE = 100;
+               
+               /// <summary> Indicates that the server response to a request is ambiguous.
+               /// 
+               /// <p>AMBIGUOUS_RESPONSE = 101</p>
+               /// </summary>
+               public const int AMBIGUOUS_RESPONSE = 101;
+               
+               /// <summary> Indicates that TLS is not supported on the server.
+               /// 
+               /// <p>TLS_NOT_SUPPORTED = 112</p>
+               /// </summary>
+               public const int TLS_NOT_SUPPORTED = 112;
+               
+               /*
+               * Note: Error strings have been pulled out into
+               * ResultCodeMessages.properties
+               */
+               
+               /// <summary> Constructs a default exception with no specific error information.</summary>
+               public LdapException():base()
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String, the result code,
+               /// and a server meessage.</p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// </param>
+               public LdapException(System.String messageOrKey, int resultCode, System.String serverMsg):this(messageOrKey, null, resultCode, serverMsg, null, null)
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and modifying arguments.
+               /// Additional parameters specify the result code and server message.</p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// <p>The message in the default locale is built with the supplied arguments,
+               /// which are saved to be used for building messages for other locales.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">   The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// </param>
+               public LdapException(System.String messageOrKey, System.Object[] arguments, int resultCode, System.String serverMsg):this(messageOrKey, arguments, resultCode, serverMsg, null, null)
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String.
+               /// Additional parameters specify the result code, the server message, and a
+               /// rootException which is the underlying cause of an error on the client.<p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException"> A throwable which is the underlying cause
+               /// of the LdapException.
+               /// </param>
+               public LdapException(System.String messageOrKey, int resultCode, System.String serverMsg, System.Exception rootException):this(messageOrKey, null, resultCode, serverMsg, null, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and modifying arguments.
+               /// Additional parameters specify the result code, the server message,
+               /// and a rootException which is the underlying cause of an error
+               /// on the client.</p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// <p>The message in the default locale is built with the supplied arguments,
+               /// which are saved to be used for building messages for other locales.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">   The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException"> A throwable which is the underlying cause
+               /// of the LdapException.
+               /// </param>
+               public LdapException(System.String messageOrKey, System.Object[] arguments, int resultCode, System.String serverMsg, System.Exception rootException):this(messageOrKey, arguments, resultCode, serverMsg, null, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String.
+               /// Additional parameters specify the result code, the message returned
+               /// from the server, and a matchedDN returned from the server.</p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// <br><br>
+               /// </param>
+               /// <param name="matchedDN">     The maximal subset of a specified DN which could
+               /// be matched by the server on a search operation.
+               /// </param>
+               public LdapException(System.String messageOrKey, int resultCode, System.String serverMsg, System.String matchedDN):this(messageOrKey, null, resultCode, serverMsg, matchedDN, null)
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and modifying arguments.
+               /// Additional parameters specify the result code, a message returned from
+               /// the server, and a matchedDN returned from the server.</p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// <p>The message in the default locale is built with the supplied arguments,
+               /// which are saved to be used for building messages for other locales.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">   The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// <br><br>
+               /// </param>
+               /// <param name="matchedDN">     The maximal subset of a specified DN which could
+               /// be matched by the server on a search operation.
+               /// </param>
+               public LdapException(System.String messageOrKey, System.Object[] arguments, int resultCode, System.String serverMsg, System.String matchedDN):this(messageOrKey, arguments, resultCode, serverMsg, matchedDN, null)
+               {
+                       return ;
+               }
+               
+               /// <summary> <p>Constructs an exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and modifying arguments.
+               /// Additional parameters specify the result code, a message returned
+               /// from the server, a matchedDN returned from
+               /// the server, and a rootException which is the underlying cause of an error
+               /// on the client.</p>
+               /// 
+               /// <p>The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.</p>
+               /// 
+               /// <p>The message in the default locale is built with the supplied arguments,
+               /// which are saved to be used for building messages for other locales.</p>
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">   The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMsg">    Error message specifying additional information
+               /// from the server
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException"> A throwable which is the underlying cause
+               /// of the LdapException.
+               /// <br><br>
+               /// </param>
+               /// <param name="matchedDN">     The maximal subset of a specified DN which could
+               /// be matched by the server on a search operation.
+               /// </param>
+               /* package */
+               internal LdapException(System.String messageOrKey, System.Object[] arguments, int resultCode, System.String serverMsg, System.String matchedDN, System.Exception rootException)
+                           //:base(Novell.Directory.Ldap.Utilclass.ResourcesHandler.getMessage(messageOrKey, arguments))
+               //Once resorcehandler starts working properly need to uncomment
+               {
+                       this.messageOrKey = messageOrKey;
+                       this.arguments = arguments;
+                       this.resultCode = resultCode;
+                       this.rootException = rootException;
+                       this.matchedDN = matchedDN;
+                       this.serverMessage = serverMsg;
+                       return ;
+               }
+               
+               /// <summary> Returns a string representing the result code in the default
+               /// locale.
+               /// 
+               /// </summary>
+               /// <returns> The message for the result code in the LdapException object.
+               /// </returns>
+               public virtual System.String resultCodeToString()
+               {
+                       return ResourcesHandler.getResultString(resultCode);
+               }
+               
+               /// <summary> Returns a string representing the specified result code in the default
+               /// locale.
+               /// 
+               /// </summary>
+               /// <param name="code"> The result code for which a message is to be returned.
+               /// 
+               /// </param>
+               /// <returns> The message corresponding to the specified result code, or
+               /// or null if the message is not available for the default locale.
+               /// </returns>
+               public static System.String resultCodeToString(int code)
+               {
+                       return ResourcesHandler.getResultString(code);
+               }
+               
+               /// <summary> Returns a string representing the result code in the
+               /// specified locale.
+               /// 
+               /// </summary>
+               /// <param name="locale">The locale in which to render the error message.
+               /// 
+               /// </param>
+               /// <returns> A message corresponding to the result code in the
+               /// specified locale, or null if the message is not available
+               /// for the requested locale.
+               /// </returns>
+               public virtual System.String resultCodeToString(System.Globalization.CultureInfo locale)
+               {
+                       return ResourcesHandler.getResultString(resultCode, locale);
+               }
+               
+               /// <summary> Returns a string representing the specified error code in the
+               /// specified locale.
+               /// 
+               /// </summary>
+               /// <param name="code">    The result code for which a message is to be
+               /// returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="locale">  The locale in which to render the message.
+               /// 
+               /// </param>
+               /// <returns> A message corresponding to the result code in the
+               /// specified locale, or null if the message is not available
+               /// for the requested locale.
+               /// </returns>
+               public static System.String resultCodeToString(int code, System.Globalization.CultureInfo locale)
+               {
+                       return ResourcesHandler.getResultString(code, locale);
+               }
+               
+               /// <summary> returns a string of information about the exception and the
+               /// the nested exceptions, if any.
+               /// </summary>
+               public override System.String ToString()
+               {
+                       return getExceptionString("LdapException");
+               }
+               
+               /// <summary> builds a string of information about the exception and the
+               /// the nested exceptions, if any.
+               /// 
+               /// </summary>
+               /// <param name="exception">The name of the exception class
+               /// </param>
+               /* package */
+               internal virtual System.String getExceptionString(System.String exception)
+               {
+                       System.String tmsg;
+                       
+                       // Format the basic exception information
+                       
+                       // Craft a string from the resouce file
+                       System.String msg = ResourcesHandler.getMessage("TOSTRING", new System.Object[]{exception, base.Message, resultCode, resultCodeToString()});
+                       // If found no string from resource file, use a default string
+                       if (msg.ToUpper().Equals("TOSTRING".ToUpper()))
+                       {
+                               msg = exception + ": (" + resultCode + ") " + resultCodeToString();
+                       }
+                       
+                       // Add server message
+                       if (((System.Object) serverMessage != null) && (serverMessage.Length != 0))
+                       {
+                               tmsg = ResourcesHandler.getMessage("SERVER_MSG", new System.Object[]{exception, serverMessage});
+                               // If found no string from resource file, use a default string
+                               if (tmsg.ToUpper().Equals("SERVER_MSG".ToUpper()))
+                               {
+                                       tmsg = exception + ": Server Message: " + serverMessage;
+                               }
+                               
+                               msg = msg + '\n' + tmsg;
+                       }
+                       
+                       // Add Matched DN message
+                       if ((System.Object) matchedDN != null)
+                       {
+                               tmsg = ResourcesHandler.getMessage("MATCHED_DN", new System.Object[]{exception, matchedDN});
+                               // If found no string from resource file, use a default string
+                               if (tmsg.ToUpper().Equals("MATCHED_DN".ToUpper()))
+                               {
+                                       tmsg = exception + ": Matched DN: " + matchedDN;
+                               }
+                               
+                               msg = msg + '\n' + tmsg;
+                       }
+                       
+                       if (rootException != null)
+                       {
+                               msg = msg + '\n' + rootException.ToString();
+                       }
+                       return msg;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedOperation.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedOperation.cs
new file mode 100755 (executable)
index 0000000..cae68f0
--- /dev/null
@@ -0,0 +1,129 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapExtendedOperation.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Encapsulates an ID which uniquely identifies a particular extended
+       /// operation, known to a particular server, and the data associated
+       /// with that extended operation.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#extendedOperation">
+       /// </seealso>
+       public class LdapExtendedOperation : System.ICloneable
+       {
+               
+               private System.String oid;
+               private sbyte[] vals;
+               
+               /// <summary> Constructs a new object with the specified object ID and data.
+               /// 
+               /// </summary>
+               /// <param name="oid">    The unique identifier of the operation.
+               /// 
+               /// </param>
+               /// <param name="vals">   The operation-specific data of the operation.
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               public LdapExtendedOperation(System.String oid, sbyte[] vals)
+               {
+                       this.oid = oid;
+                       this.vals = vals;
+               }
+               
+               /// <summary> Returns a clone of this object.
+               /// 
+               /// </summary>
+               /// <returns> clone of this object.
+               /// </returns>
+               public System.Object Clone()
+               {
+                       try
+                       {
+                               System.Object newObj = base.MemberwiseClone();
+//                             Array.Copy((System.Array)SupportClass.ToByteArray( this.vals), 0, (System.Array)SupportClass.ToByteArray( ((LdapExtendedOperation) newObj).vals), 0, this.vals.Length);
+                               Array.Copy((System.Array)this.vals, 0, (System.Array)((LdapExtendedOperation) newObj).vals, 0, this.vals.Length);
+                               return newObj;
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+               }
+               
+               /// <summary> Returns the unique identifier of the operation.
+               /// 
+               /// </summary>
+               /// <returns> The OID (object ID) of the operation.
+               /// </returns>
+               public virtual System.String getID()
+               {
+                       return oid;
+               }
+               
+               /// <summary> Returns a reference to the operation-specific data.
+               /// 
+               /// </summary>
+               /// <returns> The operation-specific data.
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               public virtual sbyte[] getValue()
+               {
+                       return vals;
+               }
+               
+               /// <summary>  Sets the value for the operation-specific data.
+               /// 
+               /// </summary>
+               /// <param name="newVals"> The byte array of operation-specific data.
+               /// </param>
+               [CLSCompliantAttribute(false)]
+               protected internal virtual void  setValue(sbyte[] newVals)
+               {
+                       this.vals = newVals;
+                       return ;
+               }
+               
+               /// <summary>  Resets the OID for the operation to a new value
+               /// 
+               /// </summary>
+               /// <param name="newoid"> The new OID for the operation
+               /// </param>
+               protected internal virtual void  setID(System.String newoid)
+               {
+                       this.oid = newoid;
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedRequest.cs
new file mode 100755 (executable)
index 0000000..9e5ce01
--- /dev/null
@@ -0,0 +1,95 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapExtendedRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Asn1OctetString = Novell.Directory.Ldap.Asn1.Asn1OctetString;
+using Asn1Tagged = Novell.Directory.Ldap.Asn1.Asn1Tagged;
+using RfcExtendedRequest = Novell.Directory.Ldap.Rfc2251.RfcExtendedRequest;
+using RfcLdapOID = Novell.Directory.Ldap.Rfc2251.RfcLdapOID;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap Extended Request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso> 
+   /*
+       *       ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+       *               requestName      [0] LdapOID,
+       *               requestValue     [1] OCTET STRING OPTIONAL }
+       */
+       public class LdapExtendedRequest:LdapMessage
+       {
+               /// <summary> Retrieves an extended operation from this request</summary>
+               /// <returns> extended operation represented in this request.
+               /// </returns>
+               virtual public LdapExtendedOperation ExtendedOperation
+               {
+                       get
+                       {
+                               RfcExtendedRequest xreq = (RfcExtendedRequest) this.Asn1Object.get_Renamed(1);
+                               
+                               //Zeroth element is the OID, element one is the value
+                               Asn1Tagged tag = (Asn1Tagged) xreq.get_Renamed(0);
+                               RfcLdapOID oid = (RfcLdapOID) tag.taggedValue();
+                               System.String requestID = oid.stringValue();
+                               
+                               sbyte[] requestValue = null;
+                               if (xreq.size() >= 2)
+                               {
+                                       tag = (Asn1Tagged) xreq.get_Renamed(1);
+                                       Asn1OctetString value_Renamed = (Asn1OctetString) tag.taggedValue();
+                                       requestValue = value_Renamed.byteValue();
+                               }
+                               return new LdapExtendedOperation(requestID, requestValue);
+                       }
+                       
+               }
+               /// <summary> Constructs an LdapExtendedRequest.
+               /// <br><br>
+               /// </summary>
+               /// <param name="op"> The object which contains (1) an identifier of an extended
+               /// operation which should be recognized by the particular Ldap
+               /// server this client is connected to, and (2) an operation-
+               /// specific sequence of octet strings or BER-encoded values.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">Any controls that apply to the extended request
+               /// or null if none.
+               /// </param>
+               public LdapExtendedRequest(LdapExtendedOperation op, LdapControl[] cont):base(LdapMessage.EXTENDED_REQUEST, new RfcExtendedRequest(new RfcLdapOID(op.getID()), (op.getValue() != null)?new Asn1OctetString(op.getValue()):null), cont)
+               {
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedResponse.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapExtendedResponse.cs
new file mode 100755 (executable)
index 0000000..a69d2ee
--- /dev/null
@@ -0,0 +1,94 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapExtendedResponse.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Asn1;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Encapsulates the response returned by an Ldap server on an
+       /// asynchronous extended operation request.  It extends LdapResponse.
+       /// 
+       /// The response can contain the OID of the extension, an octet string
+       /// with the operation's data, both, or neither.
+       /// </summary>
+       public class LdapExtendedResponse:LdapResponse
+       {
+               /// <summary> Returns the message identifier of the response.
+               /// 
+               /// </summary>
+               /// <returns> OID of the response.
+               /// </returns>
+               virtual public System.String ID
+               {
+                       get
+                       {
+                               RfcLdapOID respOID = ((RfcExtendedResponse) message.Response).ResponseName;
+                               if (respOID == null)
+                                       return null;
+                               return respOID.stringValue();
+                       }
+                       
+               }
+               /// <summary> Returns the value part of the response in raw bytes.
+               /// 
+               /// </summary>
+               /// <returns> The value of the response.
+               /// </returns>
+               [CLSCompliantAttribute(false)]
+               virtual public sbyte[] Value
+               {
+                       get
+                       {
+                               Asn1OctetString tempString = ((RfcExtendedResponse) message.Response).Response;
+                               if (tempString == null)
+                                       return null;
+                               else
+                                       return (tempString.byteValue());
+                       }
+                       
+               }
+               
+               /// <summary> Creates an LdapExtendedResponse object which encapsulates
+               /// a server response to an asynchronous extended operation request.
+               /// 
+               /// </summary>
+               /// <param name="message"> The RfcLdapMessage to convert to an
+               /// LdapExtendedResponse object.
+               /// </param>
+               public LdapExtendedResponse(RfcLdapMessage message):base(message)
+               {
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapLocalException.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapLocalException.cs
new file mode 100755 (executable)
index 0000000..f4c0da3
--- /dev/null
@@ -0,0 +1,163 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapLocalException.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  Represents an Ldap exception that is not a result of a server response.</summary>
+       public class LdapLocalException:LdapException
+       {
+               /// <summary> Constructs a default exception with no specific error information.</summary>
+               public LdapLocalException():base()
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a local exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and the result code.
+               /// <br>
+               /// The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// </param>
+               public LdapLocalException(System.String messageOrKey, int resultCode):base(messageOrKey, resultCode, (System.String) null)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a local exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and modifying arguments.
+               /// Additional parameters specify the result code.
+               /// <br>
+               /// The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.
+               /// <br>
+               /// The message in the default locale is built with the supplied arguments,
+               /// which are saved to be used for building messages for other locales.
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">   The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// </param>
+               public LdapLocalException(System.String messageOrKey, System.Object[] arguments, int resultCode):base(messageOrKey, arguments, resultCode, (System.String) null)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a local exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String.
+               /// Additional parameters specify the result code and a rootException which
+               /// is the underlying cause of an error on the client.
+               /// <br>
+               /// The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException"> A throwable which is the underlying cause
+               /// of the LdapException.
+               /// </param>
+               public LdapLocalException(System.String messageOrKey, int resultCode, System.Exception rootException):base(messageOrKey, resultCode, null, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a local exception with a detailed message obtained from the
+               /// specified <code>MessageOrKey</code> String and modifying arguments.
+               /// Additional parameters specify the result code
+               /// and a rootException which is the underlying cause of an error
+               /// on the client.
+               /// <br>
+               /// The String is used either as a message key to obtain a localized
+               /// messsage from ExceptionMessages, or if there is no key in the
+               /// resource matching the text, it is used as the detailed message itself.
+               /// <br>
+               /// The message in the default locale is built with the supplied arguments,
+               /// which are saved to be used for building messages for other locales.
+               /// 
+               /// </summary>
+               /// <param name="messageOrKey"> Key to addition result information, a key into
+               /// ExceptionMessages, or the information
+               /// itself if the key doesn't exist.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">   The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">   The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException"> A throwable which is the underlying cause
+               /// of the LdapException.
+               /// </param>
+               public LdapLocalException(System.String messageOrKey, System.Object[] arguments, int resultCode, System.Exception rootException):base(messageOrKey, arguments, resultCode, null, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> returns a string of information about the exception and the
+               /// the nested exceptions, if any.
+               /// </summary>
+               public override System.String ToString()
+               {
+                       // Format the basic exception information
+                       return getExceptionString("LdapLocalException");
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapMessage.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapMessage.cs
new file mode 100755 (executable)
index 0000000..50c2aac
--- /dev/null
@@ -0,0 +1,676 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapMessage.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> The base class for Ldap request and response messages.
+       /// 
+       /// <p>Subclassed by response messages used in asynchronous operations.
+       /// 
+       /// 
+       /// </summary>
+       public class LdapMessage
+       {
+               /// <summary> Returns the LdapMessage request associated with this response</summary>
+               virtual internal LdapMessage RequestingMessage
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return message.RequestingMessage;
+                       }
+                       
+               }
+               /// <summary> Returns any controls in the message.</summary>
+               virtual public LdapControl[] Controls
+               {
+                       get
+                       {
+                               
+/*                             LdapControl[] controls = null;
+                               RfcControls asn1Ctrls = message.Controls;
+                               
+                               if (asn1Ctrls != null)
+                               {
+                                       controls = new LdapControl[asn1Ctrls.size()];
+                                       for (int i = 0; i < asn1Ctrls.size(); i++)
+                                       {
+                                               RfcControl rfcCtl = (RfcControl) asn1Ctrls.get_Renamed(i);
+                                               System.String oid = rfcCtl.ControlType.stringValue();
+                                               sbyte[] value_Renamed = rfcCtl.ControlValue.byteValue();
+                                               bool critical = rfcCtl.Criticality.booleanValue();
+                                               
+                                               controls[i] = controlFactory(oid, critical, value_Renamed);
+                                       }
+                               }
+
+                               return controls;
+*/
+                               LdapControl[] controls = null;
+                               RfcControls asn1Ctrls = message.Controls;
+                               
+                               // convert from RFC 2251 Controls to LDAPControl[].
+                               if (asn1Ctrls != null)
+                               {
+                                       controls = new LdapControl[asn1Ctrls.size()];
+                                       for (int i = 0; i < asn1Ctrls.size(); i++)
+                                       {
+                                               
+                                               /*
+                                               * At this point we have an RfcControl which needs to be
+                                               * converted to the appropriate Response Control.  This requires
+                                               * calling the constructor of a class that extends LDAPControl.
+                                               * The controlFactory method searches the list of registered
+                                               * controls and if a match is found calls the constructor
+                                               * for that child LDAPControl. Otherwise, it returns a regular
+                                               * LDAPControl object.
+                                               *
+                                               * Question: Why did we not call the controlFactory method when
+                                               * we were parsing the control. Answer: By the time the
+                                               * code realizes that we have a control it is already too late.
+                                               */
+                                               RfcControl rfcCtl = (RfcControl) asn1Ctrls.get_Renamed(i);
+                                               System.String oid = rfcCtl.ControlType.stringValue();
+                                               sbyte[] value_Renamed = rfcCtl.ControlValue.byteValue();
+                                               bool critical = rfcCtl.Criticality.booleanValue();
+                                               
+                                               /* Return from this call should return either an LDAPControl
+                                               * or a class extending LDAPControl that implements the
+                                               * appropriate registered response control
+                                               */
+                                               controls[i] = controlFactory(oid, critical, value_Renamed);
+                                       }
+                               }
+                               return controls;
+
+                       }
+                       
+               }
+
+               /// <summary> Returns the message ID.  The message ID is an integer value
+               /// identifying the Ldap request and its response.
+               /// </summary>
+               virtual public int MessageID
+               {
+                       get
+                       {
+                               if (imsgNum == - 1)
+                               {
+                                       imsgNum = message.MessageID;
+                               }
+                               return imsgNum;
+                       }
+                       
+               }
+               /// <summary> Returns the Ldap operation type of the message.
+               /// 
+               /// <p>The type is one of the following:</p>
+               /// <ul>
+               /// <li>BIND_REQUEST            = 0;</li>
+               /// <li>BIND_RESPONSE           = 1;</li>
+               /// <li>UNBIND_REQUEST          = 2;</li>
+               /// <li>SEARCH_REQUEST          = 3;</li>
+               /// <li>SEARCH_RESPONSE         = 4;</li>
+               /// <li>SEARCH_RESULT           = 5;</li>
+               /// <li>MODIFY_REQUEST          = 6;</li>
+               /// <li>MODIFY_RESPONSE         = 7;</li>
+               /// <li>ADD_REQUEST             = 8;</li>
+               /// <li>ADD_RESPONSE            = 9;</li>
+               /// <li>DEL_REQUEST             = 10;</li>
+               /// <li>DEL_RESPONSE            = 11;</li>
+               /// <li>MODIFY_RDN_REQUEST      = 12;</li>
+               /// <li>MODIFY_RDN_RESPONSE     = 13;</li>
+               /// <li>COMPARE_REQUEST         = 14;</li>
+               /// <li>COMPARE_RESPONSE        = 15;</li>
+               /// <li>ABANDON_REQUEST         = 16;</li>
+               /// <li>SEARCH_RESULT_REFERENCE = 19;</li>
+               /// <li>EXTENDED_REQUEST        = 23;</li>
+               /// <li>EXTENDED_RESPONSE       = 24;</li>
+               /// </ul>
+               /// 
+               /// </summary>
+               /// <returns> The operation type of the message.
+               /// </returns>
+               virtual public int Type
+               {
+                       get
+                       {
+                               if (messageType == - 1)
+                               {
+                                       messageType = message.Type;
+                               }
+                               return messageType;
+                       }
+                       
+               }
+               /// <summary> Indicates whether the message is a request or a response
+               /// 
+               /// </summary>
+               /// <returns> true if the message is a request, false if it is a response,
+               /// a search result, or a search result reference.
+               /// </returns>
+               virtual public bool Request
+               {
+                       get
+                       {
+                               return message.isRequest();
+                       }
+                       
+               }
+               /// <summary> Returns the RFC 2251 LdapMessage composed in this object.</summary>
+               virtual internal RfcLdapMessage Asn1Object
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return message;
+                       }
+                       
+               }
+               private System.String Name
+               {
+                       get
+                       {
+                               System.String name;
+                               switch (Type)
+                               {
+                                       
+                                       case SEARCH_RESPONSE: 
+                                               name = "LdapSearchResponse";
+                                               break;
+                                       
+                                       case SEARCH_RESULT: 
+                                               name = "LdapSearchResult";
+                                               break;
+                                       
+                                       case SEARCH_REQUEST: 
+                                               name = "LdapSearchRequest";
+                                               break;
+                                       
+                                       case MODIFY_REQUEST: 
+                                               name = "LdapModifyRequest";
+                                               break;
+                                       
+                                       case MODIFY_RESPONSE: 
+                                               name = "LdapModifyResponse";
+                                               break;
+                                       
+                                       case ADD_REQUEST: 
+                                               name = "LdapAddRequest";
+                                               break;
+                                       
+                                       case ADD_RESPONSE: 
+                                               name = "LdapAddResponse";
+                                               break;
+                                       
+                                       case DEL_REQUEST: 
+                                               name = "LdapDelRequest";
+                                               break;
+                                       
+                                       case DEL_RESPONSE: 
+                                               name = "LdapDelResponse";
+                                               break;
+                                       
+                                       case MODIFY_RDN_REQUEST: 
+                                               name = "LdapModifyRDNRequest";
+                                               break;
+                                       
+                                       case MODIFY_RDN_RESPONSE: 
+                                               name = "LdapModifyRDNResponse";
+                                               break;
+                                       
+                                       case COMPARE_REQUEST: 
+                                               name = "LdapCompareRequest";
+                                               break;
+                                       
+                                       case COMPARE_RESPONSE: 
+                                               name = "LdapCompareResponse";
+                                               break;
+                                       
+                                       case BIND_REQUEST: 
+                                               name = "LdapBindRequest";
+                                               break;
+                                       
+                                       case BIND_RESPONSE: 
+                                               name = "LdapBindResponse";
+                                               break;
+                                       
+                                       case UNBIND_REQUEST: 
+                                               name = "LdapUnbindRequest";
+                                               break;
+                                       
+                                       case ABANDON_REQUEST: 
+                                               name = "LdapAbandonRequest";
+                                               break;
+                                       
+                                       case SEARCH_RESULT_REFERENCE: 
+                                               name = "LdapSearchResultReference";
+                                               break;
+                                       
+                                       case EXTENDED_REQUEST: 
+                                               name = "LdapExtendedRequest";
+                                               break;
+                                       
+                                       case EXTENDED_RESPONSE: 
+                                               name = "LdapExtendedResponse";
+                                               break;
+                                       
+                                       default: 
+                                               throw new System.SystemException("LdapMessage: Unknown Type " + Type);
+                                       
+                               }
+                               return name;
+                       }
+                       
+               }
+               /// <summary> Retrieves the identifier tag for this message.
+               /// 
+               /// <p>An identifier can be associated with a message with the
+               /// <code>setTag</code> method.
+               /// Tags are set by the application and not by the API or the server.
+               /// If a server response <code>isRequest() == false</code> has no tag,
+               /// the tag associated with the corresponding server request is used.</p>
+               /// 
+               /// </summary>
+               /// <returns> the identifier associated with this message or <code>null</code>
+               /// if none.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setTag">
+               /// </seealso>
+               /// <seealso cref="#isRequest">
+               /// </seealso>
+               /// <summary> Sets a string identifier tag for this message.
+               /// 
+               /// <p>This method allows an API to set a tag and later identify messages
+               /// by retrieving the tag associated with the message.
+               /// Tags are set by the application and not by the API or the server.
+               /// Message tags are not included with any message sent to or received
+               /// from the server.</p>
+               /// 
+               /// <p>Tags set on a request to the server
+               /// are automatically associated with the response messages when they are
+               /// received by the API and transferred to the application.
+               /// The application can explicitly set a different value in a
+               /// response message.</p>
+               /// 
+               /// <p>To set a value in a server request, for example an
+               /// {@link LdapSearchRequest}, you must create the object,
+               /// set the tag, and use the
+               /// {@link LdapConnection#sendRequest LdapConnection.sendRequest()}
+               /// method to send it to the server.</p>
+               /// 
+               /// </summary>
+               /// <param name="stringTag"> the String assigned to identify this message.
+               /// 
+               /// </param>
+               /// <seealso cref="#getTag">
+               /// </seealso>
+               /// <seealso cref="#isRequest">
+               /// </seealso>
+               virtual public System.String Tag
+               {
+                       get
+                       {
+                               if ((System.Object) this.stringTag != null)
+                               {
+                                       return this.stringTag;
+                               }
+                               if (Request)
+                               {
+                                       return null;
+                               }
+                               LdapMessage m = this.RequestingMessage;
+                               if (m == null)
+                               {
+                                       return null;
+                               }
+                               return m.stringTag;
+                       }
+                       
+                       set
+                       {
+                               this.stringTag = value;
+                               return ;
+                       }
+                       
+               }
+               
+               /// <summary> A bind request operation.
+               /// 
+               /// <p>BIND_REQUEST = 0</p>
+               /// </summary>
+               public const int BIND_REQUEST = 0;
+               
+               /// <summary> A bind response operation.
+               /// 
+               /// <p>BIND_RESPONSE = 1</p>
+               /// </summary>
+               public const int BIND_RESPONSE = 1;
+               
+               /// <summary> An unbind request operation.
+               /// 
+               /// <p>UNBIND_REQUEST = 2</p>
+               /// </summary>
+               public const int UNBIND_REQUEST = 2;
+               
+               /// <summary> A search request operation.
+               /// 
+               /// <p>SEARCH_REQUEST = 3</p>
+               /// </summary>
+               public const int SEARCH_REQUEST = 3;
+               
+               /// <summary> A search response containing data.
+               /// 
+               /// <p>SEARCH_RESPONSE = 4</p>
+               /// </summary>
+               public const int SEARCH_RESPONSE = 4;
+               
+               /// <summary> A search result message - contains search status.
+               /// 
+               /// <p>SEARCH_RESULT = 5</p>
+               /// </summary>
+               public const int SEARCH_RESULT = 5;
+               
+               /// <summary> A modify request operation.
+               /// 
+               /// <p>MODIFY_REQUEST = 6</p>
+               /// </summary>
+               public const int MODIFY_REQUEST = 6;
+               
+               /// <summary> A modify response operation.
+               /// 
+               /// <p>MODIFY_RESPONSE = 7</p>
+               /// </summary>
+               public const int MODIFY_RESPONSE = 7;
+               
+               /// <summary> An add request operation.
+               /// 
+               /// <p>ADD_REQUEST = 8</p>
+               /// </summary>
+               public const int ADD_REQUEST = 8;
+               
+               /// <summary> An add response operation.
+               /// 
+               /// <p>ADD_RESONSE = 9</p>
+               /// </summary>
+               public const int ADD_RESPONSE = 9;
+               
+               /// <summary> A delete request operation.
+               /// 
+               /// <p>DEL_REQUEST = 10</p>
+               /// </summary>
+               public const int DEL_REQUEST = 10;
+               
+               /// <summary> A delete response operation.
+               /// 
+               /// <p>DEL_RESONSE = 11</p>
+               /// </summary>
+               public const int DEL_RESPONSE = 11;
+               
+               /// <summary> A modify RDN request operation.
+               /// 
+               /// <p>MODIFY_RDN_REQUEST = 12</p>
+               /// </summary>
+               public const int MODIFY_RDN_REQUEST = 12;
+               
+               /// <summary> A modify RDN response operation.
+               /// 
+               /// <p>MODIFY_RDN_RESPONSE = 13</p>
+               /// </summary>
+               public const int MODIFY_RDN_RESPONSE = 13;
+               
+               /// <summary> A compare result operation.
+               /// 
+               /// <p>COMPARE_REQUEST = 14</p>
+               /// </summary>
+               public const int COMPARE_REQUEST = 14;
+               
+               /// <summary> A compare response operation.
+               /// 
+               /// <p>COMPARE_RESPONSE = 15</p>
+               /// </summary>
+               public const int COMPARE_RESPONSE = 15;
+               
+               /// <summary> An abandon request operation.
+               /// 
+               /// <p>ABANDON_REQUEST = 16</p>
+               /// </summary>
+               public const int ABANDON_REQUEST = 16;
+               
+               
+               /// <summary> A search result reference operation.
+               /// 
+               /// <p>SEARCH_RESULT_REFERENCE = 19</p>
+               /// </summary>
+               public const int SEARCH_RESULT_REFERENCE = 19;
+               
+               /// <summary> An extended request operation.
+               /// 
+               /// <p>EXTENDED_REQUEST = 23</p>
+               /// </summary>
+               public const int EXTENDED_REQUEST = 23;
+               
+               /// <summary> An extended response operation.
+               /// 
+               /// <p>EXTENDED_RESONSE = 24</p>
+               /// </summary>
+               public const int EXTENDED_RESPONSE = 24;
+               
+               /// <summary> A request or response message for an asynchronous Ldap operation.</summary>
+               protected internal RfcLdapMessage message;
+               
+               /// <summary> Lock object to protect counter for message numbers</summary>
+               /*
+               private static Object msgLock = new Object();
+               */
+               
+               /// <summary> Counters used to construct request message #'s, unique for each request
+               /// Will be enabled after ASN.1 conversion
+               /// </summary>
+               /*
+               private static int msgNum = 0; // Ldap Request counter
+               */
+               private int imsgNum = - 1; // This instance LdapMessage number
+               
+               private int messageType = - 1;
+               
+               /* application defined tag to identify this message */
+               private System.String stringTag = null;
+               
+               /// <summary> Dummy constuctor</summary>
+               /* package */
+               internal LdapMessage()
+               {
+                       return ;
+               }
+               
+               /// <summary> Creates an LdapMessage when sending a protocol operation and sends
+               /// some optional controls with the message.
+               /// 
+               /// </summary>
+               /// <param name="op">The operation type of message.
+               /// <br><br>
+               /// </param>
+               /// <param name="controls">The controls to use with the operation.
+               /// 
+               /// </param>
+               /// <seealso cref="#getType">
+               /// </seealso>
+               /*package*/
+               internal LdapMessage(int type, RfcRequest op, LdapControl[] controls)
+               {
+                       
+                       // Get a unique number for this request message
+                       
+                       messageType = type;
+                       RfcControls asn1Ctrls = null;
+                       if (controls != null)
+                       {
+                               // Move LdapControls into an RFC 2251 Controls object.
+                               asn1Ctrls = new RfcControls();
+                               for (int i = 0; i < controls.Length; i++)
+                               {
+//                                     asn1Ctrls.add(null);
+                                       asn1Ctrls.add(controls[i].Asn1Object);
+                               }
+                       }
+                       
+                       // create RFC 2251 LdapMessage
+                       message = new RfcLdapMessage(op, asn1Ctrls);
+                       return ;
+               }
+               
+               /// <summary> Creates an Rfc 2251 LdapMessage when the libraries receive a response
+               /// from a command.
+               /// 
+               /// </summary>
+               /// <param name="message">A response message.
+               /// </param>
+               protected internal LdapMessage(RfcLdapMessage message)
+               {
+                       this.message = message;
+                       return ;
+               }
+               
+               /// <summary> Returns a mutated clone of this LdapMessage,
+               /// replacing base dn, filter.
+               /// 
+               /// </summary>
+               /// <param name="dn">the base dn
+               /// <br><br>
+               /// </param>
+               /// <param name="filter">the filter
+               /// <br><br>
+               /// </param>
+               /// <param name="reference">true if a search reference
+               /// 
+               /// </param>
+               /// <returns> the object representing the new message
+               /// </returns>
+               /* package */
+               internal LdapMessage Clone(System.String dn, System.String filter, bool reference)
+               {
+                       return new LdapMessage((RfcLdapMessage) message.dupMessage(dn, filter, reference));
+               }
+               
+               /// <summary> Instantiates an LdapControl.  We search through our list of
+               /// registered controls.  If we find a matchiing OID we instantiate
+               /// that control by calling its contructor.  Otherwise we default to
+               /// returning a regular LdapControl object
+               /// 
+               /// </summary>
+               private LdapControl controlFactory(System.String oid, bool critical, sbyte[] value_Renamed)
+               {
+//                     throw new NotImplementedException();
+                       RespControlVector regControls = LdapControl.RegisteredControls;
+                       try
+                       {
+                               /*
+                               * search through the registered extension list to find the
+                               * response control class
+                               */
+                               System.Type respCtlClass = regControls.findResponseControl(oid);
+                               
+                               // Did not find a match so return default LDAPControl
+                               if (respCtlClass == null)
+                                       return new LdapControl(oid, critical, value_Renamed);
+                               
+                               /* If found, get LDAPControl constructor */
+                               System.Type[] argsClass = new System.Type[]{typeof(System.String), typeof(bool), typeof(sbyte[])};
+                               System.Object[] args = new System.Object[]{oid, critical, value_Renamed};
+                               System.Exception ex = null;
+                               try
+                               {
+                                       System.Reflection.ConstructorInfo ctlConstructor = respCtlClass.GetConstructor(argsClass);
+                                       
+                                       try
+                                       {
+                                               /* Call the control constructor for a registered Class*/
+                                               System.Object ctl = null;
+//                                             ctl = ctlConstructor.newInstance(args);
+                                               ctl = ctlConstructor.Invoke(args);
+                                               return (LdapControl) ctl;
+                                       }
+                                       catch (System.UnauthorizedAccessException e)
+                                       {
+                                               ex = e;
+                                       }
+                                       catch (System.Reflection.TargetInvocationException e)
+                                       {
+                                               ex = e;
+                                       }
+                                       catch (System.Exception e)
+                                       {
+                                               // Could not create the ResponseControl object
+                                               // All possible exceptions are ignored. We fall through
+                                               // and create a default LDAPControl object
+                                               ex = e;
+                                       }
+
+                               }
+                               catch (System.MethodAccessException e)
+                               {
+                                       // bad class was specified, fall through and return a
+                                       // default LDAPControl object
+                                       ex = e;
+                               }
+                       }
+                       catch (System.FieldAccessException e)
+                       {
+                               // No match with the OID
+                               // Do nothing. Fall through and construct a default LDAPControl object.
+                       }
+                       // If we get here we did not have a registered response control
+                       // for this oid.  Return a default LDAPControl object.
+                       return new LdapControl(oid, critical, value_Renamed);
+
+               }
+               
+               /// <summary> Creates a String representation of this object
+               /// 
+               /// </summary>
+               /// <returns> a String representation for this LdapMessage
+               /// </returns>
+               public override System.String ToString()
+               {
+                       return Name + "(" + MessageID + "): " + message.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapMessageQueue.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapMessageQueue.cs
new file mode 100755 (executable)
index 0000000..b709270
--- /dev/null
@@ -0,0 +1,286 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapMessageQueue.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using RfcLdapMessage = Novell.Directory.Ldap.Rfc2251.RfcLdapMessage;
+using ExtResponseFactory = Novell.Directory.Ldap.Utilclass.ExtResponseFactory;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  Represents a queue of incoming asynchronous messages from the server.
+       /// It is the common interface for {@link LdapResponseQueue} and
+       /// {@link LdapSearchQueue}.
+       /// </summary>
+       public abstract class LdapMessageQueue
+       {
+               /// <summary> Returns the name used for debug
+               /// 
+               /// </summary>
+               /// <returns> name of object instance used for debug
+               /// </returns>
+               virtual internal System.String DebugName
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return name;
+                       }
+                       
+               }
+               /// <summary> Returns the internal client message agent
+               /// 
+               /// </summary>
+               /// <returns> The internal client message agent
+               /// </returns>
+               virtual internal MessageAgent MessageAgent
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return agent;
+                       }
+                       
+               }
+               /// <summary> Returns the message IDs for all outstanding requests. These are requests
+               /// for which a response has not been received from the server or which
+               /// still have messages to be retrieved with getResponse.
+               /// 
+               /// <p>The last ID in the array is the messageID of the last submitted
+               /// request.</p>
+               /// 
+               /// </summary>
+               /// <returns> The message IDs for all outstanding requests.
+               /// </returns>
+               virtual public int[] MessageIDs
+               {
+                       get
+                       {
+                               return agent.MessageIDs;
+                       }
+                       
+               }
+               /// <summary> The message agent object associated with this queue</summary>
+               /* package */
+               internal MessageAgent agent;
+               
+               // Queue name used only for debug
+               /* package */
+               internal System.String name = "";
+               
+               // nameLock used to protect queueNum during increment
+               /* package */
+               internal static System.Object nameLock;
+               
+               // Queue number used only for debug
+               /* package */
+               internal static int queueNum = 0;
+               
+               /// <summary> Constructs a response queue using the specified message agent
+               /// 
+               /// </summary>
+               /// <param name="agent">The message agent to associate with this conneciton
+               /// </param>
+               /* package */
+               internal LdapMessageQueue(System.String myname, MessageAgent agent)
+               {
+                       // Get a unique connection name for debug
+                       this.agent = agent;
+                       return ;
+               }
+               
+               /// <summary> Returns the response from an Ldap request.
+               /// 
+               /// <p>The getResponse method blocks until a response is available, or until
+               /// all operations associated with the object have completed or been
+               /// canceled, and then returns the response.</p>
+               /// 
+               /// <p>The application is responsible to determine the type of message
+               /// returned.</p>
+               /// 
+               /// </summary>
+               /// <returns> The response.
+               /// 
+               /// </returns>
+               /// <seealso cref="LdapResponse">
+               /// </seealso>
+               /// <seealso cref="LdapSearchResult">
+               /// </seealso>
+               /// <seealso cref="LdapSearchResultReference">
+               /// 
+               /// </seealso>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapMessage getResponse()
+               {
+                       return getResponse(null);
+               }
+               
+               /// <summary> Returns the response from an Ldap request for a particular message ID.
+               /// 
+               /// <p>The getResponse method blocks until a response is available
+               /// for a particular message ID, or until all operations associated
+               /// with the object have completed or been canceled, and
+               /// then returns the response.  If there is no outstanding operation for
+               /// the message ID (or if it is zero or a negative number),
+               /// IllegalArgumentException is thrown.
+               /// 
+               /// <p>The application is responsible to determine the type of message
+               /// returned.</p>
+               /// 
+               /// </summary>
+               /// <param name="msgid">query for responses for a specific message request
+               /// 
+               /// </param>
+               /// <returns> The response from the server.
+               /// 
+               /// </returns>
+               /// <seealso cref="LdapResponse">
+               /// </seealso>
+               /// <seealso cref="LdapSearchResult">
+               /// </seealso>
+               /// <seealso cref="LdapSearchResultReference">
+               /// 
+               /// </seealso>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               public virtual LdapMessage getResponse(System.Int32 msgid)
+               {
+                       return getResponse(new Integer32(msgid));
+               }
+               
+               /// <summary> Private implementation of getResponse.
+               /// Has an Integer object as a parameter so we can distinguish
+               /// the null and the message number case
+               /// </summary>
+//             private LdapMessage getResponse(System.Int32 msgid)
+               private LdapMessage getResponse(Integer32 msgid)
+               {
+                       System.Object resp;
+                       RfcLdapMessage message;
+                       LdapMessage response;
+                       if ((resp = agent.getLdapMessage(msgid)) == null)
+                       {
+                               // blocks
+                               return null; // no messages from this agent
+                       }
+                       // Local error occurred, contains a LocalException
+                       if (resp is LdapResponse)
+                       {
+                               return (LdapMessage) resp;
+                       }
+                       // Normal message handling
+                       message = (RfcLdapMessage) resp;
+                       switch (message.Type)
+                       {
+                               
+                               case LdapMessage.SEARCH_RESPONSE: 
+                                       response = new LdapSearchResult(message);
+                                       break;
+                               
+                               case LdapMessage.SEARCH_RESULT_REFERENCE: 
+                                       response = new LdapSearchResultReference(message);
+                                       break;
+                               
+                               case LdapMessage.EXTENDED_RESPONSE: 
+                                       ExtResponseFactory fac = new ExtResponseFactory();
+                                       response = ExtResponseFactory.convertToExtendedResponse(message);
+                                       break;
+                               
+                               default: 
+                                       response = new LdapResponse(message);
+                                       break;
+                               
+                       }
+                       return response;
+               }
+               
+               /// <summary> Reports true if any response has been received from the server and not
+               /// yet retrieved with getResponse.  If getResponse has been used to
+               /// retrieve all messages received to this point, then isResponseReceived
+               /// returns false.
+               /// 
+               /// </summary>
+               /// <returns> true if a response is available to be retrieved via getResponse,
+               /// otherwise false.
+               /// 
+               /// </returns>
+               /// <seealso cref="#getResponse()">
+               /// </seealso>
+               public virtual bool isResponseReceived()
+               {
+                       return agent.isResponseReceived();
+               }
+               
+               /// <summary> Reports true if a response has been received from the server for
+               /// a particular message ID but not yet retrieved with getResponse.  If
+               /// there is no outstanding operation for the message ID (or if it is
+               /// zero or a negative number), IllegalArgumentException is thrown.
+               /// 
+               /// </summary>
+               /// <param name="msgid">   A particular message ID to query for available responses.
+               /// 
+               /// </param>
+               /// <returns> true if a response is available to be retrieved via getResponse
+               /// for the specified message ID, otherwise false.
+               /// 
+               /// </returns>
+               /// <seealso cref="#getResponse(int)">
+               /// </seealso>
+               public virtual bool isResponseReceived(int msgid)
+               {
+                       return agent.isResponseReceived(msgid);
+               }
+               
+               /// <summary> Reports true if all results have been received for a particular
+               /// message id.
+               /// 
+               /// <p>If the search result done has been received from the server for the
+               /// message id, it reports true.  There may still be messages waiting to be
+               /// retrieved by the applcation with getResponse.<p>
+               /// 
+               /// @throws IllegalArgumentException if there is no outstanding operation
+               /// for the message ID,
+               /// </summary>
+               public virtual bool isComplete(int msgid)
+               {
+                       return agent.isComplete(msgid);
+               }
+               static LdapMessageQueue()
+               {
+                       nameLock = new System.Object();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModification.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModification.cs
new file mode 100755 (executable)
index 0000000..dde7fa2
--- /dev/null
@@ -0,0 +1,173 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapModification.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> A single add, delete, or replace operation to an LdapAttribute.
+       /// 
+       /// <p>An LdapModification contains information on the type of modification
+       /// being performed, the name of the attribute to be replaced, and the new
+       /// value.  Multiple modifications are expressed as an array of modifications,
+       /// i.e., <code>LdapModification[]</code>.</p>
+       /// 
+       /// <p>An LdapModification or an LdapModification array enable you to modify
+       /// an attribute of an Ldap entry. The entire array of modifications must
+       /// be performed by the server as a single atomic operation in the order they
+       /// are listed. No changes are made to the directory unless all the operations
+       /// succeed. If all succeed, a success result is returned to the application.
+       /// It should be noted that if the connection fails during a modification,
+       /// it is indeterminate whether the modification occurred or not.</p>
+       /// 
+       /// <p>There are three types of modification operations: Add, Delete,
+       /// and Replace.</p>
+       /// 
+       /// <p><b>Add: </b>Creates the attribute if it doesn't exist, and adds
+       /// the specified values. This operation must contain at least one value, and
+       /// all values of the attribute must be unique.</p>
+       /// 
+       /// <p><b>Delete: </b>Deletes specified values from the attribute. If no
+       /// values are specified, or if all existing values of the attribute are
+       /// specified, the attribute is removed. Mandatory attributes cannot be
+       /// removed.</p>
+       /// 
+       /// <p><b>Replace: </b>Creates the attribute if necessary, and replaces
+       /// all existing values of the attribute with the specified values.
+       /// If you wish to keep any existing values of a multi-valued attribute,
+       /// you must include these values in the replace operation.
+       /// A replace operation with no value will remove the entire attribute if it
+       /// exists, and is ignored if the attribute does not exist.</p>
+       /// 
+       /// <p>Additional information on Ldap modifications is available in section 4.6
+       /// of <a href="http://www.ietf.org/rfc/rfc2251.txt">rfc2251.txt</a></p>
+       /// 
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#modify">
+       /// </seealso>
+       /// <seealso cref="LdapAttribute">
+       /// </seealso>
+       public class LdapModification
+       {
+               /// <summary> Returns the attribute to modify, with any existing values.
+               /// 
+               /// </summary>
+               /// <returns> The attribute to modify.
+               /// </returns>
+               virtual public LdapAttribute Attribute
+               {
+                       get
+                       {
+                               return attr;
+                       }
+                       
+               }
+               /// <summary> Returns the type of modification specified by this object.
+               /// 
+               /// <p>The type is one of the following:</p>
+               /// <ul>
+               /// <li>LdapModification.ADD</li>
+               /// <li>LdapModification.DELETE</li>
+               /// <li>LdapModification.REPLACE</li>
+               /// </ul>
+               /// 
+               /// </summary>
+               /// <returns> The type of modification specified by this object.
+               /// </returns>
+               virtual public int Op
+               {
+                       get
+                       {
+                               return op;
+                       }
+                       
+               }
+               
+               private int op;
+               private LdapAttribute attr;
+               
+               /// <summary> Adds the listed values to the given attribute, creating
+               /// the attribute if it does not already exist.
+               /// 
+               /// <p>ADD = 0</p>
+               /// </summary>
+               public const int ADD = 0;
+               
+               /// <summary> Deletes the listed values from the given attribute,
+               /// removing the entire attribute (1) if no values are listed or
+               /// (2) if all current values of the attribute are listed for
+               /// deletion.
+               /// 
+               /// <p>DELETE = 1</p>
+               /// </summary>
+               public const int DELETE = 1;
+               
+               /// <summary> Replaces all existing values of the given attribute
+               /// with the new values listed, creating the attribute if it
+               /// does not already exist.
+               /// 
+               /// <p> A replace with no value deletes the entire attribute if it
+               /// exists, and is ignored if the attribute does not exist. </p>
+               /// 
+               /// <p>REPLACE = 2</p>
+               /// </summary>
+               public const int REPLACE = 2;
+               
+               /// <summary> Specifies a modification to be made to an attribute.
+               /// 
+               /// </summary>
+               /// <param name="op">      The type of modification to make, which can be
+               /// one of the following:
+               /// <ul>
+               /// <li>LdapModification.ADD - The value should be added to
+               /// the attribute</li>
+               /// 
+               /// <li>LdapModification.DELETE - The value should be removed
+               /// from the attribute </li>
+               /// 
+               /// <li>LdapModification.REPLACE - The value should replace all
+               /// existing values of the
+               /// attribute </li>
+               /// </ul><br>
+               /// </param>
+               /// <param name="attr">    The attribute to modify.
+               /// 
+               /// </param>
+               public LdapModification(int op, LdapAttribute attr)
+               {
+                       this.op = op;
+                       this.attr = attr;
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModifyDNRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModifyDNRequest.cs
new file mode 100755 (executable)
index 0000000..d842190
--- /dev/null
@@ -0,0 +1,156 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapModifyDNRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap ModifyDN request
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso> 
+   /*
+       *       ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+       *               entry           LdapDN,
+       *               newrdn          RelativeLdapDN,
+       *               deleteoldrdn    BOOLEAN,
+       *               newSuperior     [0] LdapDN OPTIONAL }
+       */
+       public class LdapModifyDNRequest:LdapMessage
+       {
+               /// <summary> Returns the dn of the entry to rename or move in the directory
+               /// 
+               /// </summary>
+               /// <returns> the dn of the entry to rename or move
+               /// </returns>
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return Asn1Object.RequestDN;
+                       }
+                       
+               }
+               /// <summary> Returns the newRDN of the entry to rename or move in the directory
+               /// 
+               /// </summary>
+               /// <returns> the newRDN of the entry to rename or move
+               /// </returns>
+               virtual public System.String NewRDN
+               {
+                       get
+                       {
+                               // Get the RFC request object for this request
+                               RfcModifyDNRequest req = (RfcModifyDNRequest) Asn1Object.getRequest();
+                               RfcRelativeLdapDN relDN = (RfcRelativeLdapDN) req.toArray()[1];
+                               return relDN.stringValue();
+                       }
+                       
+               }
+               /// <summary> Returns the DeleteOldRDN flag that applies to the entry to rename or
+               /// move in the directory
+               /// 
+               /// </summary>
+               /// <returns> the DeleteOldRDN flag for the entry to rename or move
+               /// </returns>
+               virtual public bool DeleteOldRDN
+               {
+                       get
+                       {
+                               // Get the RFC request object for this request
+                               RfcModifyDNRequest req = (RfcModifyDNRequest) Asn1Object.getRequest();
+                               Asn1Boolean delOld = (Asn1Boolean) req.toArray()[2];
+                               return delOld.booleanValue();
+                       }
+                       
+               }
+               /// <summary> Returns the ParentDN for the entry move in the directory
+               /// 
+               /// </summary>
+               /// <returns> the ParentDN for the entry to move, or <dd>null</dd>
+               /// if the request is not a move.
+               /// </returns>
+               virtual public System.String ParentDN
+               {
+                       get
+                       {
+                               // Get the RFC request object for this request
+                               RfcModifyDNRequest req = (RfcModifyDNRequest) Asn1Object.getRequest();
+                               Asn1Object[] seq = req.toArray();
+                               if ((seq.Length < 4) || (seq[3] == null))
+                               {
+                                       return null;
+                               }
+                               RfcLdapDN parentDN = (RfcLdapDN) req.toArray()[3];
+                               return parentDN.stringValue();
+                       }
+                       
+               }
+               /// <summary> Constructs a ModifyDN (rename) Request.
+               /// 
+               /// </summary>
+               /// <param name="dn">            The current distinguished name of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newRdn">        The new relative distinguished name for the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="newParentdn">   The distinguished name of an existing entry which
+               /// is to be the new parent of the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="deleteOldRdn">  If true, the old name is not retained as an
+               /// attribute value. If false, the old name is
+               /// retained as an attribute value.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">           Any controls that apply to the modifyDN request,
+               /// or null if none.
+               /// </param>
+               public LdapModifyDNRequest(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapControl[] cont):base(LdapMessage.MODIFY_RDN_REQUEST, new RfcModifyDNRequest(new RfcLdapDN(dn), new RfcRelativeLdapDN(newRdn), new Asn1Boolean(deleteOldRdn), ((System.Object) newParentdn != null)?new RfcLdapDN(newParentdn):null), cont)
+               {
+                       return ;
+               }
+               
+               /// <summary> Return an Asn1 representation of this mod DN request
+               /// 
+               /// #return an Asn1 representation of this object
+               /// </summary>
+               public override System.String ToString()
+               {
+                       return Asn1Object.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModifyRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapModifyRequest.cs
new file mode 100755 (executable)
index 0000000..9d63e3b
--- /dev/null
@@ -0,0 +1,183 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapModifyRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Modification Request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso>
+   /*
+       *       ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+       *               object          LdapDN,
+       *               modification    SEQUENCE OF SEQUENCE {
+       *                       operation       ENUMERATED {
+       *                                               add     (0),
+       *                                               delete  (1),
+       *                                               replace (2) },
+       *                       modification    AttributeTypeAndValues } }
+       */
+       public class LdapModifyRequest:LdapMessage
+       {
+               /// <summary> Returns of the dn of the entry to modify in the directory
+               /// 
+               /// </summary>
+               /// <returns> the dn of the entry to modify
+               /// </returns>
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return Asn1Object.RequestDN;
+                       }
+                       
+               }
+               /// <summary> Constructs the modifications associated with this request
+               /// 
+               /// </summary>
+               /// <returns> an array of LdapModification objects
+               /// </returns>
+               virtual public LdapModification[] Modifications
+               {
+                       get
+                       {
+                               // Get the RFC request object for this request
+                               RfcModifyRequest req = (RfcModifyRequest) Asn1Object.getRequest();
+                               // get beginning sequenceOf modifications
+                               Asn1SequenceOf seqof = req.Modifications;
+                               Asn1Object[] mods = seqof.toArray();
+                               LdapModification[] modifications = new LdapModification[mods.Length];
+                               // Process each modification
+                               for (int m = 0; m < mods.Length; m++)
+                               {
+                                       // Each modification consists of a mod type and a sequence
+                                       // containing the attr name and a set of values
+                                       Asn1Sequence opSeq = (Asn1Sequence) mods[m];
+                                       if (opSeq.size() != 2)
+                                       {
+                                               throw new System.SystemException("LdapModifyRequest: modification " + m + " is wrong size: " + opSeq.size());
+                                       }
+                                       // Contains operation and sequence for the attribute
+                                       Asn1Object[] opArray = opSeq.toArray();
+                                       Asn1Enumerated asn1op = (Asn1Enumerated) opArray[0];
+                                       // get the operation
+                                       int op = asn1op.intValue();
+                                       Asn1Sequence attrSeq = (Asn1Sequence) opArray[1];
+                                       Asn1Object[] attrArray = attrSeq.toArray();
+                                       RfcAttributeDescription aname = (RfcAttributeDescription) attrArray[0];
+                                       System.String name = aname.stringValue();
+                                       Asn1SetOf avalue = (Asn1SetOf) attrArray[1];
+                                       Asn1Object[] valueArray = avalue.toArray();
+                                       LdapAttribute attr = new LdapAttribute(name);
+                                       
+                                       for (int v = 0; v < valueArray.Length; v++)
+                                       {
+                                               RfcAttributeValue rfcV = (RfcAttributeValue) valueArray[v];
+                                               attr.addValue(rfcV.byteValue());
+                                       }
+                                       
+                                       modifications[m] = new LdapModification(op, attr);
+                               }
+                               return modifications;
+                       }
+                       
+               }
+               /// <summary> Constructs an Ldap Modify request.
+               /// 
+               /// </summary>
+               /// <param name="dn">        The distinguished name of the entry to modify.
+               /// <br><br>
+               /// </param>
+               /// <param name="mods">      The changes to be made to the entry.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">       Any controls that apply to the modify request,
+               /// or null if none.
+               /// </param>
+               public LdapModifyRequest(System.String dn, LdapModification[] mods, LdapControl[] cont):base(LdapMessage.MODIFY_REQUEST, new RfcModifyRequest(new RfcLdapDN(dn), encodeModifications(mods)), cont)
+               {
+                       return ;
+               }
+               
+               /// <summary> Encode an array of LdapModifications to ASN.1.
+               /// 
+               /// </summary>
+               /// <param name="mods">an array of LdapModification objects
+               /// 
+               /// </param>
+               /// <returns> an Asn1SequenceOf object containing the modifications.
+               /// </returns>
+               static private Asn1SequenceOf encodeModifications(LdapModification[] mods)
+               {
+                       // Convert Java-API LdapModification[] to RFC2251 SEQUENCE OF SEQUENCE
+                       Asn1SequenceOf rfcMods = new Asn1SequenceOf(mods.Length);
+                       for (int i = 0; i < mods.Length; i++)
+                       {
+                               LdapAttribute attr = mods[i].Attribute;
+                               
+                               // place modification attribute values in Asn1SetOf
+                               Asn1SetOf vals = new Asn1SetOf(attr.size());
+                               if (attr.size() > 0)
+                               {
+                                       System.Collections.IEnumerator attrEnum = attr.ByteValues;
+                                       while (attrEnum.MoveNext())
+                                       {
+                                               vals.add(new RfcAttributeValue((sbyte[]) attrEnum.Current));
+                                       }
+                               }
+                               
+                               // create SEQUENCE containing mod operation and attr type and vals
+                               Asn1Sequence rfcMod = new Asn1Sequence(2);
+                               rfcMod.add(new Asn1Enumerated(mods[i].Op));
+                               rfcMod.add(new RfcAttributeTypeAndValues(new RfcAttributeDescription(attr.Name), vals));
+                               
+                               // place SEQUENCE into SEQUENCE OF
+                               rfcMods.add(rfcMod);
+                       }
+                       return rfcMods;
+               }
+               
+               /// <summary> Return an Asn1 representation of this modify request
+               /// 
+               /// #return an Asn1 representation of this object
+               /// </summary>
+               public override System.String ToString()
+               {
+                       return Asn1Object.ToString();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapReferralException.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapReferralException.cs
new file mode 100755 (executable)
index 0000000..6824a1a
--- /dev/null
@@ -0,0 +1,297 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapReferralException.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  Thrown when a server returns a referral and when a referral has not
+       /// been followed.  It contains a list of URL strings corresponding
+       /// to the referrals or search continuation references received on an Ldap
+       /// operation.
+       /// </summary>
+       public class LdapReferralException:LdapException
+       {
+               /// <summary> Sets a referral that could not be processed
+               /// 
+               /// </summary>
+               /// <param name="url">The referral URL that could not be processed.
+               /// </param>
+               virtual public System.String FailedReferral
+               {
+                       /* Gets the referral that could not be processed.  If multiple referrals
+                       * could not be processed, the method returns one of them.
+                       *
+                       * @return the referral that could not be followed.
+                       */
+                       
+                       get
+                       {
+                               return failedReferral;
+                       }
+                       
+                       set
+                       {
+                               failedReferral = value;
+                               return ;
+                       }
+                       
+               }
+               
+               private System.String failedReferral = null;
+               private System.String[] referrals = null;
+               
+               /// <summary> Constructs a default exception with no specific error information.</summary>
+               public LdapReferralException():base()
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a default exception with a specified string as additional
+               /// information.
+               /// 
+               /// <p>This form is used for lower-level errors.</p>
+               /// 
+               /// </summary>
+               /// <param name="message">The additional error information.
+               /// </param>
+               public LdapReferralException(System.String message):base(message, LdapException.REFERRAL, (System.String) null)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a default exception with a specified string as additional
+               /// information.
+               /// 
+               /// <p>This form is used for lower-level errors.</p>
+               /// 
+               /// <br><br>
+               /// </summary>
+               /// <param name="arguments">    The modifying arguments to be included in the
+               /// message string.
+               /// 
+               /// </param>
+               /// <param name="message">The additional error information.
+               /// </param>
+               public LdapReferralException(System.String message, System.Object[] arguments):base(message, arguments, LdapException.REFERRAL, (System.String) null)
+               {
+                       return ;
+               }
+               /// <summary> Constructs a default exception with a specified string as additional
+               /// information and an exception that indicates a failure to follow a
+               /// referral. This excepiton applies only to synchronous operations and
+               /// is thrown only on receipt of a referral when the referral was not
+               /// followed.
+               /// 
+               /// </summary>
+               /// <param name="message">The additional error information.
+               /// 
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException">An exception which caused referral following to fail.
+               /// </param>
+               public LdapReferralException(System.String message, System.Exception rootException):base(message, LdapException.REFERRAL, null, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs a default exception with a specified string as additional
+               /// information and an exception that indicates a failure to follow a
+               /// referral. This excepiton applies only to synchronous operations and
+               /// is thrown only on receipt of a referral when the referral was not
+               /// followed.
+               /// 
+               /// </summary>
+               /// <param name="message">The additional error information.
+               /// 
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">    The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="rootException">An exception which caused referral following to fail.
+               /// </param>
+               public LdapReferralException(System.String message, System.Object[] arguments, System.Exception rootException):base(message, arguments, LdapException.REFERRAL, null, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs an exception with a specified error string, result code, and
+               /// an error message from the server.
+               /// 
+               /// </summary>
+               /// <param name="message">       The additional error information.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">    The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMessage"> Error message specifying additional information
+               /// from the server.
+               /// </param>
+               public LdapReferralException(System.String message, int resultCode, System.String serverMessage):base(message, resultCode, serverMessage)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs an exception with a specified error string, result code, and
+               /// an error message from the server.
+               /// 
+               /// </summary>
+               /// <param name="message">       The additional error information.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">     The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">    The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMessage"> Error message specifying additional information
+               /// from the server.
+               /// </param>
+               public LdapReferralException(System.String message, System.Object[] arguments, int resultCode, System.String serverMessage):base(message, arguments, resultCode, serverMessage)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs an exception with a specified error string, result code,
+               /// an error message from the server, and an exception that indicates
+               /// a failure to follow a referral.
+               /// 
+               /// </summary>
+               /// <param name="message">       The additional error information.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">    The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMessage"> Error message specifying additional information
+               /// from the server.
+               /// </param>
+               public LdapReferralException(System.String message, int resultCode, System.String serverMessage, System.Exception rootException):base(message, resultCode, serverMessage, rootException)
+               {
+                       return ;
+               }
+               /// <summary> Constructs an exception with a specified error string, result code,
+               /// an error message from the server, and an exception that indicates
+               /// a failure to follow a referral.
+               /// 
+               /// </summary>
+               /// <param name="message">       The additional error information.
+               /// <br><br>
+               /// </param>
+               /// <param name="arguments">     The modifying arguments to be included in the
+               /// message string.
+               /// <br><br>
+               /// </param>
+               /// <param name="resultCode">    The result code returned.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverMessage"> Error message specifying additional information
+               /// from the server.
+               /// </param>
+               public LdapReferralException(System.String message, System.Object[] arguments, int resultCode, System.String serverMessage, System.Exception rootException):base(message, arguments, resultCode, serverMessage, rootException)
+               {
+                       return ;
+               }
+               
+               /// <summary> Gets the list of referral URLs (Ldap URLs to other servers) returned by
+               /// the Ldap server.
+               /// 
+               /// The referral list may include URLs of a type other than ones for an Ldap
+               /// server (for example, a referral URL other than ldap://something).</p>
+               /// 
+               /// </summary>
+               /// <returns> The list of URLs that comprise this referral
+               /// </returns>
+               public virtual System.String[] getReferrals()
+               {
+                       return referrals;
+               }
+               
+               /// <summary> Sets the list of referrals
+               /// 
+               /// </summary>
+               /// <param name="urls">the list of referrals returned by the Ldap server in a
+               /// single response.
+               /// </param>
+               /* package */
+               internal virtual void  setReferrals(System.String[] urls)
+               {
+                       referrals = urls;
+                       return ;
+               }
+               
+               /// <summary> returns a string of information about the exception and the
+               /// the nested exceptions, if any.
+               /// </summary>
+               public override System.String ToString()
+               {
+                       System.String msg, tmsg;
+                       
+                       // Format the basic exception information
+                       msg = getExceptionString("LdapReferralException");
+                       
+                       // Add failed referral information
+                       if ((System.Object) failedReferral != null)
+                       {
+                               tmsg = ResourcesHandler.getMessage("FAILED_REFERRAL", new System.Object[]{"LdapReferralException", failedReferral});
+                               // If found no string from resource file, use a default string
+                               if (tmsg.ToUpper().Equals("SERVER_MSG".ToUpper()))
+                               {
+                                       tmsg = "LdapReferralException: Failed Referral: " + failedReferral;
+                               }
+                               msg = msg + '\n' + tmsg;
+                       }
+                       
+                       // Add referral information, display all the referrals in the list
+                       if (referrals != null)
+                       {
+                               for (int i = 0; i < referrals.Length; i++)
+                               {
+                                       tmsg = ResourcesHandler.getMessage("REFERRAL_ITEM", new System.Object[]{"LdapReferralException", referrals[i]});
+                                       // If found no string from resource file, use a default string
+                                       if (tmsg.ToUpper().Equals("SERVER_MSG".ToUpper()))
+                                       {
+                                               tmsg = "LdapReferralException: Referral: " + referrals[i];
+                                       }
+                                       msg = msg + '\n' + tmsg;
+                               }
+                       }
+                       return msg;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapReferralHandler.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapReferralHandler.cs
new file mode 100755 (executable)
index 0000000..9e01520
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapReferralHandler.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Shared ancestor to the two types of referral objects - LdapBindHandler and
+       /// LdapAuthHandler.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapBindHandler">
+       /// </seealso>
+       /// <seealso cref="LdapAuthHandler">
+       /// 
+       /// </seealso>
+       public interface LdapReferralHandler
+               {
+               }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapResponse.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapResponse.cs
new file mode 100755 (executable)
index 0000000..59c2cd1
--- /dev/null
@@ -0,0 +1,482 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapResponse.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  A message received from an LdapServer
+       /// in response to an asynchronous request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#search">
+       /// </seealso>
+       
+       /*
+       * Note: Exceptions generated by the reader thread are returned
+       * to the application as an exception in an LdapResponse.  Thus
+       * if <code>exception</code> has a value, it is not a server response,
+       * but instad an exception returned to the application from the API.
+       */
+       public class LdapResponse:LdapMessage
+       {
+               /// <summary> Returns any error message in the response.
+               /// 
+               /// </summary>
+               /// <returns> Any error message in the response.
+               /// </returns>
+               virtual public System.String ErrorMessage
+               {
+                       get
+                       {
+                               if (exception != null)
+                               {
+                                       return exception.LdapErrorMessage;
+                               }
+
+/*                             RfcResponse resp=(RfcResponse)( message.Response);
+                               if(resp == null)
+                                       Console.WriteLine(" Response is null");
+                               else
+                                       Console.WriteLine(" Response is non null");
+                               string str=resp.getErrorMessage().stringValue();
+                               if( str==null)
+                                        Console.WriteLine("str is null..");
+                               Console.WriteLine(" Response is non null" + str);
+                               return str;
+*/
+                               return ((RfcResponse) message.Response).getErrorMessage().stringValue();
+                       }
+                       
+               }
+               /// <summary> Returns the partially matched DN field from the server response,
+               /// if the response contains one.
+               /// 
+               /// </summary>
+               /// <returns> The partially matched DN field, if the response contains one.
+               /// 
+               /// </returns>
+               virtual public System.String MatchedDN
+               {
+                       get
+                       {
+                               if (exception != null)
+                               {
+                                       return exception.MatchedDN;
+                               }
+                               return ((RfcResponse) message.Response).getMatchedDN().stringValue();
+                       }
+                       
+               }
+               /// <summary> Returns all referrals in a server response, if the response contains any.
+               /// 
+               /// </summary>
+               /// <returns> All the referrals in the server response.
+               /// </returns>
+               virtual public System.String[] Referrals
+               {
+                       get
+                       {
+                               System.String[] referrals = null;
+                               RfcReferral ref_Renamed = ((RfcResponse) message.Response).getReferral();
+                               
+                               if (ref_Renamed == null)
+                               {
+                                       referrals = new System.String[0];
+                               }
+                               else
+                               {
+                                       // convert RFC 2251 Referral to String[]
+                                       int size = ref_Renamed.size();
+                                       referrals = new System.String[size];
+                                       for (int i = 0; i < size; i++)
+                                       {
+                                               System.String aRef = ((Asn1OctetString) ref_Renamed.get_Renamed(i)).stringValue();
+                                               try
+                                               {
+                                                       // get the referral URL
+                                                       LdapUrl urlRef = new LdapUrl(aRef);
+                                                       if ((System.Object) urlRef.getDN() == null)
+                                                       {
+                                                               RfcLdapMessage origMsg = base.Asn1Object.RequestingMessage.Asn1Object;
+                                                               System.String dn;
+                                                               if ((System.Object) (dn = origMsg.RequestDN) != null)
+                                                               {
+                                                                       urlRef.setDN(dn);
+                                                                       aRef = urlRef.ToString();
+                                                               }
+                                                       }
+                                               }
+                                               catch (System.UriFormatException mex)
+                                               {
+                                                       ;
+                                               }
+                                               finally
+                                               {
+                                                       referrals[i] = aRef;
+                                               }
+                                       }
+                               }
+                               return referrals;
+                       }
+                       
+               }
+               /// <summary> Returns the result code in a server response.
+               /// 
+               /// <p> For a list of result codes, see the LdapException class. </p>
+               /// 
+               /// </summary>
+               /// <returns> The result code.
+               /// </returns>
+               virtual public int ResultCode
+               {
+                       get
+                       {
+                               if (exception != null)
+                               {
+                                       return exception.ResultCode;
+                               }
+                               return ((RfcResponse) message.Response).getResultCode().intValue();
+                       }
+                       
+               }
+               /// <summary> Checks the resultCode and generates the appropriate exception or
+               /// null if success.
+               /// </summary>
+               virtual internal LdapException ResultException
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               LdapException ex = null;
+                               switch (ResultCode)
+                               {
+                                       
+                                       case LdapException.SUCCESS: 
+                                       case LdapException.COMPARE_TRUE: 
+                                       case LdapException.COMPARE_FALSE: 
+                                               break;
+                                       
+                                       case LdapException.REFERRAL: 
+                                               System.String[] refs = Referrals;
+                                               ex = new LdapReferralException("Automatic referral following not enabled", LdapException.REFERRAL, ErrorMessage);
+                                               ((LdapReferralException) ex).setReferrals(refs);
+                                               break;
+                                       
+                                       default: 
+                                               ex = new LdapException(LdapException.resultCodeToString(ResultCode), ResultCode, ErrorMessage, MatchedDN);
+//                                             ex = new LdapException("49", 49, "hello error", "hi error..");
+                                               break;
+                                       
+                               }
+                               return ex;
+                       }
+                       
+               }
+               /// <summary> Returns any controls in the message.
+               /// 
+               /// </summary>
+               /// <seealso cref="com.novell.ldap.LdapMessage#getControls()">
+               /// </seealso>
+               override public LdapControl[] Controls
+               {
+                       get
+                       {
+                               if (exception != null)
+                               {
+                                       return null;
+                               }
+                               return base.Controls;
+                       }
+                       
+               }
+               /// <summary> Returns the message ID.
+               /// 
+               /// </summary>
+               /// <seealso cref="com.novell.ldap.LdapMessage#getMessageID()">
+               /// </seealso>
+               override public int MessageID
+               {
+                       get
+                       {
+                               if (exception != null)
+                               {
+                                       return exception.MessageID;
+                               }
+                               return base.MessageID;
+                       }
+                       
+               }
+               /// <summary> Returns the Ldap operation type of the message.
+               /// 
+               /// </summary>
+               /// <returns> The operation type of the message.
+               /// 
+               /// </returns>
+               /// <seealso cref="com.novell.ldap.LdapMessage#getType()">
+               /// </seealso>
+               override public int Type
+               {
+                       get
+                       {
+                               if (exception != null)
+                               {
+                                       return exception.ReplyType;
+                               }
+                               return base.Type;
+                       }
+                       
+               }
+               /// <summary> Returns an embedded exception response
+               /// 
+               /// </summary>
+               /// <returns> an embedded exception if any
+               /// </returns>
+               virtual internal LdapException Exception
+               {
+                       /*package*/
+                       
+                       get
+                       {
+                               return exception;
+                       }
+                       
+               }
+               /// <summary> Indicates the referral instance being followed if the
+               /// connection created to follow referrals.
+               /// 
+               /// </summary>
+               /// <returns> the referral being followed
+               /// </returns>
+               virtual internal ReferralInfo ActiveReferral
+               {
+                       /*package*/
+                       
+                       get
+                       {
+                               return activeReferral;
+                       }
+                       
+               }
+               private InterThreadException exception = null;
+               private ReferralInfo activeReferral;
+               
+               /// <summary> Creates an LdapResponse using an LdapException.
+               /// Used to wake up the user following an abandon.
+               /// Note: The abandon doesn't have to be user initiated
+               /// but may be the result of error conditions.
+               /// <br>
+               /// Referral information is available if this connection created solely
+               /// to follow a referral.
+               /// 
+               /// </summary>
+               /// <param name="ex"> The exception
+               /// <br><br>
+               /// </param>
+               /// <param name="activeReferral"> The referral actually used to create the
+               /// connection
+               /// </param>
+               public LdapResponse(InterThreadException ex, ReferralInfo activeReferral)
+               {
+                       exception = ex;
+                       this.activeReferral = activeReferral;
+                       
+                       return ;
+               }
+               
+               /// <summary> Creates a response LdapMessage when receiving an asynchronous
+               /// response from a server.
+               /// 
+               /// </summary>
+               /// <param name="message"> The RfcLdapMessage from a server.
+               /// </param>
+               /*package*/
+               internal LdapResponse(RfcLdapMessage message):base(message)
+               {
+                       return ;
+               }
+               
+               /// <summary> Creates a SUCCESS response LdapMessage. Typically the response
+               /// comes from a source other than a BER encoded Ldap message,
+               /// such as from DSML.  Other values which are allowed in a response
+               /// are set to their empty values.
+               /// 
+               /// </summary>
+               /// <param name="type"> The message type as defined in LdapMessage.
+               /// 
+               /// </param>
+               /// <seealso cref="LdapMessage">
+               /// </seealso>
+               public LdapResponse(int type):this(type, LdapException.SUCCESS, null, null, null, null)
+               {
+                       return ;
+               }
+               
+               /// <summary> Creates a response LdapMessage from parameters. Typically the data
+               /// comes from a source other than a BER encoded Ldap message,
+               /// such as from DSML.
+               /// 
+               /// </summary>
+               /// <param name="type"> The message type as defined in LdapMessage.
+               /// 
+               /// </param>
+               /// <param name="resultCode"> The result code as defined in LdapException.
+               /// 
+               /// </param>
+               /// <param name="matchedDN">  The name of the lowest entry that was matched
+               /// for some error result codes, an empty string
+               /// or <code>null</code> if none.
+               /// 
+               /// </param>
+               /// <param name="serverMessage"> A diagnostic message returned by the server,
+               /// an empty string or <code>null</code> if none.
+               /// 
+               /// </param>
+               /// <param name="referrals">  The referral URLs returned for a REFERRAL result
+               /// code or <code>null</code> if none.
+               /// 
+               /// </param>
+               /// <param name="controls">   Any controls returned by the server or
+               /// <code>null</code> if none.
+               /// 
+               /// </param>
+               /// <seealso cref="LdapMessage">
+               /// </seealso>
+               /// <seealso cref="LdapException">
+               /// </seealso>
+               public LdapResponse(int type, int resultCode, System.String matchedDN, System.String serverMessage, System.String[] referrals, LdapControl[] controls):base(new RfcLdapMessage(RfcResultFactory(type, resultCode, matchedDN, serverMessage, referrals)))
+               {
+                       
+                       return ;
+               }
+               
+               private static Asn1Sequence RfcResultFactory(int type, int resultCode, System.String matchedDN, System.String serverMessage, System.String[] referrals)
+               {
+                       Asn1Sequence ret;
+                       
+                       if ((System.Object) matchedDN == null)
+                               matchedDN = "";
+                       if ((System.Object) serverMessage == null)
+                               serverMessage = "";
+                       
+                       switch (type)
+                       {
+                               
+                               case SEARCH_RESULT: 
+                                       ret = new RfcSearchResultDone(new Asn1Enumerated(resultCode), new RfcLdapDN(matchedDN), new RfcLdapString(serverMessage), null);
+                                       break;
+                               
+                               case BIND_RESPONSE: 
+                                       ret = null; // Not yet implemented
+                                       break;
+                               
+                               case SEARCH_RESPONSE: 
+                                       ret = null; // Not yet implemented
+                                       break;
+                               
+                               case MODIFY_RESPONSE: 
+                                       ret = new RfcModifyResponse(new Asn1Enumerated(resultCode), new RfcLdapDN(matchedDN), new RfcLdapString(serverMessage), null);
+                                       break;
+                               
+                               case ADD_RESPONSE: 
+                                       ret = new RfcAddResponse(new Asn1Enumerated(resultCode), new RfcLdapDN(matchedDN), new RfcLdapString(serverMessage), null);
+                                       break;
+                               
+                               case DEL_RESPONSE: 
+                                       ret = new RfcDelResponse(new Asn1Enumerated(resultCode), new RfcLdapDN(matchedDN), new RfcLdapString(serverMessage), null);
+                                       break;
+                               
+                               case MODIFY_RDN_RESPONSE: 
+                                       ret = new RfcModifyDNResponse(new Asn1Enumerated(resultCode), new RfcLdapDN(matchedDN), new RfcLdapString(serverMessage), null);
+                                       break;
+                               
+                               case COMPARE_RESPONSE: 
+                                       ret = new RfcCompareResponse(new Asn1Enumerated(resultCode), new RfcLdapDN(matchedDN), new RfcLdapString(serverMessage), null);
+                                       break;
+                               
+                               case SEARCH_RESULT_REFERENCE: 
+                                       ret = null; // Not yet implemented
+                                       break;
+                               
+                               case EXTENDED_RESPONSE: 
+                                       ret = null; // Not yet implemented
+                                       break;
+                               
+                               default: 
+                                       throw new System.SystemException("Type " + type + " Not Supported");
+                               
+                       }
+                       return ret;
+               }
+               
+               /// <summary> Checks the resultCode and throws the appropriate exception.
+               /// 
+               /// </summary>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               /* package */
+               internal virtual void  chkResultCode()
+               {
+                       if (exception != null)
+                       {
+                               throw exception;
+                       }
+                       else
+                       {
+                               LdapException ex = ResultException;
+                               if (ex != null)
+                               {
+                                       throw ex;
+                               }
+                               return ;
+                       }
+               }
+               
+               /* Methods from LdapMessage */
+               
+               /// <summary> Indicates if this response is an embedded exception response
+               /// 
+               /// </summary>
+               /// <returns> true if contains an embedded Ldapexception
+               /// </returns>
+               /*package*/
+               internal virtual bool hasException()
+               {
+                       return (exception != null);
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapResponseQueue.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapResponseQueue.cs
new file mode 100755 (executable)
index 0000000..a6eeaa2
--- /dev/null
@@ -0,0 +1,78 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapResponseQueue.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  A mechanism for processing asynchronous messages received from a server.
+       /// It represents the message queue associated with a particular asynchronous
+       /// Ldap operation or operations.
+       /// </summary>
+       public class LdapResponseQueue:LdapMessageQueue
+       {
+               /// <summary> Constructs a response queue using the specified message agent
+               /// 
+               /// </summary>
+               /// <param name="agent">The message agent to associate with this queue
+               /// </param>
+               /* package */
+               internal LdapResponseQueue(MessageAgent agent):base("LdapResponseQueue", agent)
+               {
+                       return ;
+               }
+               
+               /// <summary> Merges two message queues.  It appends the current and
+               /// future contents from another queue to this one.
+               /// 
+               /// <p>After the operation, queue2.getMessageIDs()
+               /// returns an empty array, and its outstanding responses
+               /// have been removed and appended to this queue</p>.
+               /// 
+               /// </summary>
+               /// <param name="queue2">   The queue that is merged from.  Following
+               /// the merge, this queue object will no
+               /// longer receive any data, and calls made
+               /// to its methods will fail with a RuntimeException.
+               /// The queue can be reactivated by using it in an 
+               /// Ldap request, after which it will receive responses
+               /// for that request..
+               /// </param>
+               public virtual void  merge(LdapMessageQueue queue2)
+               {
+                       LdapResponseQueue q = (LdapResponseQueue) queue2;
+                       agent.merge(q.MessageAgent);
+                       
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchConstraints.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchConstraints.cs
new file mode 100755 (executable)
index 0000000..8e0f135
--- /dev/null
@@ -0,0 +1,430 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapSearchConstraints.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Defines the options controlling search operations.
+       /// 
+       /// <p>An LdapSearchConstraints object is always associated with an
+       /// LdapConnection object; its values can be changed with the
+       /// LdapConnection.setConstraints method, or overridden by passing
+       /// an LdapSearchConstraints object to the search operation.</p>
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConstraints">
+       /// </seealso>
+       /// <seealso cref="LdapConnection#setConstraints(LdapConstraints)">
+       /// </seealso>
+       public class LdapSearchConstraints:LdapConstraints
+       {
+               private void  InitBlock()
+               {
+                       dereference = DEREF_NEVER;
+               }
+               /// <summary> Returns the number of results to block on during receipt of search
+               /// results.
+               /// 
+               /// </p>This should be 0 if intermediate reults are not needed,
+               /// and 1 if results are to be processed as they come in. A value of
+               /// indicates block until all results are received.  Default: </p>
+               /// 
+               /// </summary>
+               /// <returns> The the number of results to block on.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setBatchSize(int)">
+               /// </seealso>
+               /// <summary>  Specifies the number of results to return in a batch.
+               /// <p>Specifying 0 means to block until all results are received.
+               /// Specifying 1 means to return results one result at a time.  Default: 1
+               /// </p>
+               /// 
+               /// <p>This should be 0 if intermediate results are not needed,
+               /// and 1 if results are to be processed as they come in.  The
+               /// default is 1.
+               /// 
+               /// </summary>
+               /// <param name="batchSize">     The number of results to block on.
+               /// 
+               /// </param>
+               /// <seealso cref="#getBatchSize()">
+               /// </seealso>
+               virtual public int BatchSize
+               {
+                       get
+                       {
+                               return batchSize;
+                       }
+                       
+                       set
+                       {
+                               this.batchSize = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Specifies when aliases should be dereferenced.
+               /// 
+               /// <p>Returns one of the following:
+               /// <ul>
+               /// <li>DEREF_NEVER</li>
+               /// <li>DEREF_FINDING</li>
+               /// <li>DEREF_SEARCHING</li>
+               /// <li>DEREF_ALWAYS</li>
+               /// </ul>
+               /// 
+               /// </summary>
+               /// <returns> The setting for dereferencing aliases.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setDereference(int)">
+               /// </seealso>
+               /// <summary> Sets a preference indicating whether or not aliases should be
+               /// dereferenced, and if so, when.
+               /// 
+               /// 
+               /// </summary>
+               /// <param name="dereference"> Specifies how aliases are dereference and can be set
+               /// to one of the following:
+               /// <ul>
+               /// <li>DEREF_NEVER - do not dereference aliases</li>
+               /// <li>DEREF_FINDING - dereference aliases when finding
+               /// the base object to start the search</li>
+               /// <li>DEREF_SEARCHING - dereference aliases when
+               /// searching but not when finding the base
+               /// object to start the search</li>
+               /// <li>DEREF_ALWAYS - dereference aliases when finding
+               /// the base object and when searching</li>
+               /// </ul>
+               /// 
+               /// </param>
+               /// <seealso cref="#getDereference()">
+               /// </seealso>
+               virtual public int Dereference
+               {
+                       get
+                       {
+                               return dereference;
+                       }
+                       
+                       set
+                       {
+                               this.dereference = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Returns the maximum number of search results to be returned for
+               /// a search operation. A value of 0 means no limit.  Default: 1000
+               /// The search operation will be terminated with an
+               /// LdapException.SIZE_LIMIT_EXCEEDED if the number of results
+               /// exceed the maximum.
+               /// 
+               /// </summary>
+               /// <returns> The value for the maximum number of results to return.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setMaxResults(int)">
+               /// </seealso>
+               /// <seealso cref="LdapException#SIZE_LIMIT_EXCEEDED">
+               /// </seealso>
+               /// <summary> Sets the maximum number of search results to be returned from a
+               /// search operation. The value 0 means no limit.  The default is 1000.
+               /// The search operation will be terminated with an
+               /// LdapException.SIZE_LIMIT_EXCEEDED if the number of results
+               /// exceed the maximum.
+               /// 
+               /// </summary>
+               /// <param name="maxResults">    Maximum number of search results to return.
+               /// 
+               /// </param>
+               /// <seealso cref="#getMaxResults()">
+               /// </seealso>
+               /// <seealso cref="LdapException#SIZE_LIMIT_EXCEEDED">
+               /// </seealso>
+               virtual public int MaxResults
+               {
+                       get
+                       {
+                               return maxResults;
+                       }
+                       
+                       set
+                       {
+                               this.maxResults = value;
+                               return ;
+                       }
+                       
+               }
+               /// <summary> Returns the maximum number of seconds that the server waits when
+               /// returning search results.
+               /// The search operation will be terminated with an
+               /// LdapException.TIME_LIMIT_EXCEEDED if the operation exceeds the time
+               /// limit.
+               /// 
+               /// </summary>
+               /// <returns> The maximum number of seconds the server waits for search'
+               /// results.
+               /// 
+               /// </returns>
+               /// <seealso cref="#setServerTimeLimit(int)">
+               /// </seealso>
+               /// <seealso cref="LdapException#TIME_LIMIT_EXCEEDED">
+               /// </seealso>
+               /// <summary> Sets the maximum number of seconds that the server is to wait when
+               /// returning search results.
+               /// The search operation will be terminated with an
+               /// LdapException.TIME_LIMIT_EXCEEDED if the operation exceeds the time
+               /// limit.
+               /// 
+               /// <p>The parameter is only recognized on search operations. </p>
+               /// 
+               /// </summary>
+               /// <param name="seconds">The number of seconds to wait for search results.
+               /// 
+               /// </param>
+               /// <seealso cref="#getServerTimeLimit()">
+               /// </seealso>
+               /// <seealso cref="LdapException#TIME_LIMIT_EXCEEDED">
+               /// </seealso>
+               virtual public int ServerTimeLimit
+               {
+                       get
+                       {
+                               return serverTimeLimit;
+                       }
+                       
+                       set
+                       {
+                               this.serverTimeLimit = value;
+                               return ;
+                       }
+                       
+               }
+               
+               private int dereference;
+               private int serverTimeLimit = 0;
+               private int maxResults = 1000;
+               private int batchSize = 1;
+               new private static System.Object nameLock; // protect agentNum
+               private static int lSConsNum = 0; // Debug, LdapConnection number
+               new private System.String name; // String name for debug
+               
+               /// <summary> Indicates that aliases are never dereferenced.
+               /// 
+               /// <p> DEREF_NEVER = 0 </p>
+               /// 
+               /// </summary>
+               /// <seealso cref="#getDereference()">
+               /// </seealso>
+               /// <seealso cref="#setDereference(int)">
+               /// </seealso>
+               public const int DEREF_NEVER = 0;
+               
+               /// <summary> Indicates that aliases are are derefrenced when
+               /// searching the entries beneath the starting point of the search,
+               /// but not when finding the starting entry.
+               /// 
+               /// <p> DEREF_SEARCHING = 1 </p>
+               /// 
+               /// </summary>
+               /// <seealso cref="#getDereference()">
+               /// </seealso>
+               /// <seealso cref="#setDereference(int)">
+               /// </seealso>
+               public const int DEREF_SEARCHING = 1;
+               
+               /// <summary> Indicates that aliases are dereferenced when
+               /// finding the starting point for the search,
+               /// but not when searching under that starting entry.
+               /// 
+               /// <p> DEREF_FINDING = 2 </p>
+               /// 
+               /// </summary>
+               /// <seealso cref="#getDereference()">
+               /// </seealso>
+               /// <seealso cref="#setDereference(int)">
+               /// </seealso>
+               public const int DEREF_FINDING = 2;
+               
+               /// <summary> Indicates that aliases are always dereferenced, both when
+               /// finding the starting point for the search, and also when
+               /// searching the entries beneath the starting entry.
+               /// 
+               /// <p> DEREF_ALWAYS = 3 </p>
+               /// 
+               /// </summary>
+               /// <seealso cref="#getDereference()">
+               /// </seealso>
+               /// <seealso cref="#setDereference(int)">
+               /// </seealso>
+               public const int DEREF_ALWAYS = 3;
+               
+               /// <summary> Constructs an LdapSearchConstraints object with a default set
+               /// of search constraints.
+               /// </summary>
+               public LdapSearchConstraints():base()
+               {
+                       InitBlock();
+                       // Get a unique connection name for debug
+               }
+               
+               /// <summary> Constructs an LdapSearchConstraints object initialized with values
+               /// from an existing constraints object (LdapConstraints
+               /// or LdapSearchConstraints).
+               /// </summary>
+               public LdapSearchConstraints(LdapConstraints cons):base(cons.TimeLimit, cons.ReferralFollowing, cons.getReferralHandler(), cons.HopLimit)
+               {
+                       InitBlock();
+                       LdapControl[] lsc = cons.getControls();
+                       if (lsc != null)
+                       {
+                               LdapControl[] generated_var = new LdapControl[lsc.Length];
+                               lsc.CopyTo(generated_var, 0);
+                               base.setControls(generated_var);
+                       }
+                       System.Collections.Hashtable lp = cons.Properties;
+                       if (lp != null)
+                       {
+                               base.Properties = (System.Collections.Hashtable) lp.Clone();
+                       }
+                       
+                       if (cons is LdapSearchConstraints)
+                       {
+                               LdapSearchConstraints scons = (LdapSearchConstraints) cons;
+                               this.serverTimeLimit = scons.ServerTimeLimit;
+                               this.dereference = scons.Dereference;
+                               this.maxResults = scons.MaxResults;
+                               this.batchSize = scons.BatchSize;
+                       }
+                       // Get a unique connection name for debug
+                       return ;
+               }
+               
+               /// <summary> Constructs a new LdapSearchConstraints object and allows the
+               /// specification operational constraints in that object.
+               /// 
+               /// </summary>
+               /// <param name="msLimit"> The maximum time in milliseconds to wait for results.
+               /// The default is 0, which means that there is no
+               /// maximum time limit. This limit is enforced for an
+               /// operation by the API, not by the server.
+               /// The operation will be abandoned and terminated by the
+               /// API with an LdapException.Ldap_TIMEOUT if the
+               /// operation exceeds the time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverTimeLimit">The maximum time in seconds that the server
+               /// should spend returning search results. This is a
+               /// server-enforced limit.  The default of 0 means
+               /// no time limit.
+               /// The operation will be terminated by the server with an
+               /// LdapException.TIME_LIMIT_EXCEEDED if the search
+               /// operation exceeds the time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="dereference">Specifies when aliases should be dereferenced.
+               /// Must be either DEREF_NEVER, DEREF_FINDING,
+               /// DEREF_SEARCHING, or DEREF_ALWAYS from this class.
+               /// Default: DEREF_NEVER
+               /// <br><br>
+               /// </param>
+               /// <param name="maxResults">The maximum number of search results to return
+               /// for a search request.
+               /// The search operation will be terminated by the server
+               /// with an LdapException.SIZE_LIMIT_EXCEEDED if the
+               /// number of results exceed the maximum.
+               /// Default: 1000
+               /// <br><br>
+               /// </param>
+               /// <param name="doReferrals">Determines whether to automatically follow
+               /// referrals or not. Specify true to follow
+               /// referrals automatically, and false to throw
+               /// an LdapException.REFERRAL if the server responds
+               /// with a referral.
+               /// It is ignored for asynchronous operations.
+               /// Default: false
+               /// <br><br>
+               /// </param>
+               /// <param name="batchSize">The number of results to return in a batch. Specifying
+               /// 0 means to block until all results are received.
+               /// Specifying 1 means to return results one result at a
+               /// time.  Default: 1
+               /// 
+               /// <br><br>
+               /// </param>
+               /// <param name="handler">  The custom authentication handler called when
+               /// LdapConnection needs to authenticate, typically on
+               /// following a referral.  A null may be specified to
+               /// indicate default authentication processing, i.e.
+               /// referrals are followed with anonymous authentication.
+               /// ThE object may be an implemention of either the
+               /// the LdapBindHandler or LdapAuthHandler interface.
+               /// It is ignored for asynchronous operations.
+               /// <br><br>
+               /// </param>
+               /// <param name="hop_limit">The maximum number of referrals to follow in a
+               /// sequence during automatic referral following.
+               /// The default value is 10. A value of 0 means no limit.
+               /// It is ignored for asynchronous operations.
+               /// The operation will be abandoned and terminated by the
+               /// API with an LdapException.REFERRAL_LIMIT_EXCEEDED if the
+               /// number of referrals in a sequence exceeds the limit.
+               /// 
+               /// </param>
+               /// <seealso cref="LdapException#Ldap_TIMEOUT">
+               /// </seealso>
+               /// <seealso cref="LdapException#REFERRAL">
+               /// </seealso>
+               /// <seealso cref="LdapException#SIZE_LIMIT_EXCEEDED">
+               /// </seealso>
+               /// <seealso cref="LdapException#TIME_LIMIT_EXCEEDED">
+               /// </seealso>
+               public LdapSearchConstraints(int msLimit, int serverTimeLimit, int dereference, int maxResults, bool doReferrals, int batchSize, LdapReferralHandler handler, int hop_limit):base(msLimit, doReferrals, handler, hop_limit)
+               {
+                       InitBlock();
+                       this.serverTimeLimit = serverTimeLimit;
+                       this.dereference = dereference;
+                       this.maxResults = maxResults;
+                       this.batchSize = batchSize;
+                       // Get a unique connection name for debug
+                       return ;
+               }
+               static LdapSearchConstraints()
+               {
+                       nameLock = new System.Object();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchQueue.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchQueue.cs
new file mode 100755 (executable)
index 0000000..2dc1e99
--- /dev/null
@@ -0,0 +1,82 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapSearchQueue.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  A mechanism for queuing asynchronous search results
+       /// received from a server.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#search">
+       /// </seealso>
+       /// <seealso cref="LdapResponseQueue">
+       /// </seealso>
+       public class LdapSearchQueue:LdapMessageQueue
+       {
+               /// <summary> Constructs a response queue using a specific client queue
+               /// 
+               /// </summary>
+               /// <param name="agent">The message agent to associate with this queue
+               /// </param>
+               /* package */
+               internal LdapSearchQueue(MessageAgent agent):base("LdapSearchQueue", agent)
+               {
+                       return ;
+               }
+               /// <summary> Merges two message queues.  It appends the current and
+               /// future contents from another queue to this one.
+               /// 
+               /// <p>After the operation, queue2.getMessageIDs()
+               /// returns an empty array, and its outstanding responses
+               /// have been removed and appended to this queue</p>.
+               /// 
+               /// </summary>
+               /// <param name="queue2">   The queue that is merged from.  Following
+               /// the merge, this queue object will no
+               /// longer receive any data, and calls made
+               /// to its methods will fail with a RuntimeException.
+               /// The queue can be reactivated by using it in an 
+               /// Ldap request, after which it will receive responses
+               /// for that request..
+               /// </param>
+               public virtual void  merge(LdapMessageQueue queue2)
+               {
+                       
+                       LdapSearchQueue q = (LdapSearchQueue) queue2;
+                       agent.merge(q.MessageAgent);
+                       
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchRequest.cs
new file mode 100755 (executable)
index 0000000..f8ebdcd
--- /dev/null
@@ -0,0 +1,405 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapSearchRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap Search request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso> 
+   /*
+       *       SearchRequest ::= [APPLICATION 3] SEQUENCE {
+       *               baseObject      LdapDN,
+       *               scope           ENUMERATED {
+       *                       baseObject              (0),
+       *                       singleLevel             (1),
+       *                       wholeSubtree            (2) },
+       *               derefAliases    ENUMERATED {
+       *                       neverDerefAliases       (0),
+       *                       derefInSearching        (1),
+       *                       derefFindingBaseObj     (2),
+       *                       derefAlways             (3) },
+       *               sizeLimit       INTEGER (0 .. maxInt),
+       *               timeLimit       INTEGER (0 .. maxInt),
+       *               typesOnly       BOOLEAN,
+       *               filter          Filter,
+       *               attributes      AttributeDescriptionList }
+       */
+       public class LdapSearchRequest:LdapMessage
+       {
+               /// <summary> Retrieves the Base DN for a search request.
+               /// 
+               /// </summary>
+               /// <returns> the base DN for a search request
+               /// </returns>
+               virtual public System.String DN
+               {
+                       get
+                       {
+                               return Asn1Object.RequestDN;
+                       }
+                       
+               }
+               /// <summary> Retrieves the scope of a search request.</summary>
+               /// <returns> scope of a search request
+               /// 
+               /// </returns>
+               /// <seealso cref="com.novell.ldap.LdapConnection#SCOPE_BASE">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapConnection#SCOPE_ONE">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapConnection#SCOPE_SUB">
+               /// </seealso>
+               virtual public int Scope
+               {
+                       get
+                       {
+                               //element number one stores the scope
+                               return ((Asn1Enumerated) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(1)).intValue();
+                       }
+                       
+               }
+               /// <summary> Retrieves the behaviour of dereferencing aliases on a search request.</summary>
+               /// <returns> integer representing how to dereference aliases
+               /// 
+               /// </returns>
+               /// <seealso cref="com.novell.ldap.LdapSearchConstraints#DEREF_ALWAYS">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapSearchConstraints#DEREF_FINDING">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapSearchConstraints#DEREF_NEVER">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapSearchConstraints#DEREF_SEARCHING">
+               /// </seealso>
+               virtual public int Dereference
+               {
+                       get
+                       {
+                               //element number two stores the dereference
+                               return ((Asn1Enumerated) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(2)).intValue();
+                       }
+                       
+               }
+               /// <summary> Retrieves the maximum number of entries to be returned on a search.
+               /// 
+               /// </summary>
+               /// <returns> Maximum number of search entries.
+               /// </returns>
+               virtual public int MaxResults
+               {
+                       get
+                       {
+                               //element number three stores the max results
+                               return ((Asn1Integer) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(3)).intValue();
+                       }
+                       
+               }
+               /// <summary> Retrieves the server time limit for a search request.
+               /// 
+               /// </summary>
+               /// <returns> server time limit in nanoseconds.
+               /// </returns>
+               virtual public int ServerTimeLimit
+               {
+                       get
+                       {
+                               //element number four stores the server time limit
+                               return ((Asn1Integer) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(4)).intValue();
+                       }
+                       
+               }
+               /// <summary> Retrieves whether attribute values or only attribute types(names) should
+               /// be returned in a search request.
+               /// </summary>
+               /// <returns> true if only attribute types (names) are returned, false if
+               /// attributes types and values are to be returned.
+               /// </returns>
+               virtual public bool TypesOnly
+               {
+                       get
+                       {
+                               //element number five stores types value
+                               return ((Asn1Boolean) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(5)).booleanValue();
+                       }
+                       
+               }
+               /// <summary> Retrieves an array of attribute names to request for in a search.</summary>
+               /// <returns> Attribute names to be searched
+               /// </returns>
+               virtual public System.String[] Attributes
+               {
+                       get
+                       {
+                               RfcAttributeDescriptionList attrs = (RfcAttributeDescriptionList) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(7);
+                               
+                               System.String[] rAttrs = new System.String[attrs.size()];
+                               for (int i = 0; i < rAttrs.Length; i++)
+                               {
+                                       rAttrs[i] = ((RfcAttributeDescription) attrs.get_Renamed(i)).stringValue();
+                               }
+                               return rAttrs;
+                       }
+                       
+               }
+               /// <summary> Creates a string representation of the filter in this search request.</summary>
+               /// <returns> filter string for this search request
+               /// </returns>
+               virtual public System.String StringFilter
+               {
+                       get
+                       {
+                               return this.RfcFilter.filterToString();
+                       }
+                       
+               }
+               /// <summary> Retrieves an SearchFilter object representing a filter for a search request</summary>
+               /// <returns> filter object for a search request.
+               /// </returns>
+               private RfcFilter RfcFilter
+               {
+                       get
+                       {
+                               return (RfcFilter) ((RfcSearchRequest) (this.Asn1Object).get_Renamed(1)).get_Renamed(6);
+                       }
+                       
+               }
+               /// <summary> Retrieves an Iterator object representing the parsed filter for
+               /// this search request.
+               /// 
+               /// <p>The first object returned from the Iterator is an Integer indicating
+               /// the type of filter component. One or more values follow the component
+               /// type as subsequent items in the Iterator. The pattern of Integer 
+               /// component type followed by values continues until the end of the
+               /// filter.</p>
+               /// 
+               /// <p>Values returned as a byte array may represent UTF-8 characters or may
+               /// be binary values. The possible Integer components of a search filter
+               /// and the associated values that follow are:
+               /// <ul>
+               /// <li>AND - followed by an Iterator value</li>
+               /// <li>OR - followed by an Iterator value</li>
+               /// <li>NOT - followed by an Iterator value</li>
+               /// <li>EQUALITY_MATCH - followed by the attribute name represented as a
+               /// String, and by the attribute value represented as a byte array</li>
+               /// <li>GREATER_OR_EQUAL - followed by the attribute name represented as a
+               /// String, and by the attribute value represented as a byte array</li>
+               /// <li>LESS_OR_EQUAL - followed by the attribute name represented as a
+               /// String, and by the attribute value represented as a byte array</li>
+               /// <li>APPROX_MATCH - followed by the attribute name represented as a
+               /// String, and by the attribute value represented as a byte array</li>
+               /// <li>PRESENT - followed by a attribute name respresented as a String</li>
+               /// <li>EXTENSIBLE_MATCH - followed by the name of the matching rule
+               /// represented as a String, by the attribute name represented
+               /// as a String, and by the attribute value represented as a 
+               /// byte array.
+               /// <li>SUBSTRINGS - followed by the attribute name represented as a
+               /// String, by one or more SUBSTRING components (INITIAL, ANY,
+               /// or FINAL) followed by the SUBSTRING value.
+               /// </ul></p>
+               /// 
+               /// </summary>
+               /// <returns> Iterator representing filter components
+               /// </returns>
+               virtual public System.Collections.IEnumerator SearchFilter
+               {
+                       get
+                       {
+                               return RfcFilter.getFilterIterator();
+                       }
+                       
+               }
+               //*************************************************************************
+               // Public variables for Filter
+               //*************************************************************************
+               
+               /// <summary> Search Filter Identifier for an AND component.</summary>
+               public const int AND = 0;
+               /// <summary> Search Filter Identifier for an OR component.</summary>
+               public const int OR = 1;
+               /// <summary> Search Filter Identifier for a NOT component.</summary>
+               public const int NOT = 2;
+               /// <summary> Search Filter Identifier for an EQUALITY_MATCH component.</summary>
+               public const int EQUALITY_MATCH = 3;
+               /// <summary> Search Filter Identifier for a SUBSTRINGS component.</summary>
+               public const int SUBSTRINGS = 4;
+               /// <summary> Search Filter Identifier for a GREATER_OR_EQUAL component.</summary>
+               public const int GREATER_OR_EQUAL = 5;
+               /// <summary> Search Filter Identifier for a LESS_OR_EQUAL component.</summary>
+               public const int LESS_OR_EQUAL = 6;
+               /// <summary> Search Filter Identifier for a PRESENT component.</summary>
+               public const int PRESENT = 7;
+               /// <summary> Search Filter Identifier for an APPROX_MATCH component.</summary>
+               public const int APPROX_MATCH = 8;
+               /// <summary> Search Filter Identifier for an EXTENSIBLE_MATCH component.</summary>
+               public const int EXTENSIBLE_MATCH = 9;
+               
+               /// <summary> Search Filter Identifier for an INITIAL component of a SUBSTRING.
+               /// Note: An initial SUBSTRING is represented as "<value>*".
+               /// </summary>
+               public const int INITIAL = 0;
+               /// <summary> Search Filter Identifier for an ANY component of a SUBSTRING.
+               /// Note: An ANY SUBSTRING is represented as "*<value>*".
+               /// </summary>
+               public const int ANY = 1;
+               /// <summary> Search Filter Identifier for a FINAL component of a SUBSTRING.
+               /// Note: A FINAL SUBSTRING is represented as "*<value>".
+               /// </summary>
+               public const int FINAL = 2;
+               
+               /// <summary> Constructs an Ldap Search Request.
+               /// 
+               /// </summary>
+               /// <param name="base">          The base distinguished name to search from.
+               /// <br><br>
+               /// </param>
+               /// <param name="scope">         The scope of the entries to search. The following
+               /// are the valid options:
+               /// <ul>
+               /// <li>SCOPE_BASE - searches only the base DN
+               /// 
+               /// <li>SCOPE_ONE - searches only entries under the base DN
+               /// 
+               /// <li>SCOPE_SUB - searches the base DN and all entries
+               /// within its subtree
+               /// </ul><br><br>
+               /// </param>
+               /// <param name="filter">        The search filter specifying the search criteria.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">         The names of attributes to retrieve.
+               /// operation exceeds the time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="dereference">Specifies when aliases should be dereferenced.
+               /// Must be one of the constants defined in
+               /// LdapConstraints, which are DEREF_NEVER,
+               /// DEREF_FINDING, DEREF_SEARCHING, or DEREF_ALWAYS.
+               /// <br><br>
+               /// </param>
+               /// <param name="maxResults">The maximum number of search results to return
+               /// for a search request.
+               /// The search operation will be terminated by the server
+               /// with an LdapException.SIZE_LIMIT_EXCEEDED if the
+               /// number of results exceed the maximum.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverTimeLimit">The maximum time in seconds that the server
+               /// should spend returning search results. This is a
+               /// server-enforced limit.  A value of 0 means
+               /// no time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="typesOnly">     If true, returns the names but not the values of
+               /// the attributes found.  If false, returns the
+               /// names and values for attributes found.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">           Any controls that apply to the search request.
+               /// or null if none.
+               /// 
+               /// </param>
+               /// <seealso cref="com.novell.ldap.LdapConnection#search">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapSearchConstraints">
+               /// </seealso>
+               public LdapSearchRequest(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, int dereference, int maxResults, int serverTimeLimit, bool typesOnly, LdapControl[] cont):base(LdapMessage.SEARCH_REQUEST, new RfcSearchRequest(new RfcLdapDN(base_Renamed), new Asn1Enumerated(scope), new Asn1Enumerated(dereference), new Asn1Integer(maxResults), new Asn1Integer(serverTimeLimit), new Asn1Boolean(typesOnly), new RfcFilter(filter), new RfcAttributeDescriptionList(attrs)), cont)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs an Ldap Search Request with a filter in Asn1 format.
+               /// 
+               /// </summary>
+               /// <param name="base">          The base distinguished name to search from.
+               /// <br><br>
+               /// </param>
+               /// <param name="scope">         The scope of the entries to search. The following
+               /// are the valid options:
+               /// <ul>
+               /// <li>SCOPE_BASE - searches only the base DN
+               /// 
+               /// <li>SCOPE_ONE - searches only entries under the base DN
+               /// 
+               /// <li>SCOPE_SUB - searches the base DN and all entries
+               /// within its subtree
+               /// </ul><br><br>
+               /// </param>
+               /// <param name="filter">        The search filter specifying the search criteria.
+               /// <br><br>
+               /// </param>
+               /// <param name="attrs">         The names of attributes to retrieve.
+               /// operation exceeds the time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="dereference">Specifies when aliases should be dereferenced.
+               /// Must be either one of the constants defined in
+               /// LdapConstraints, which are DEREF_NEVER,
+               /// DEREF_FINDING, DEREF_SEARCHING, or DEREF_ALWAYS.
+               /// <br><br>
+               /// </param>
+               /// <param name="maxResults">The maximum number of search results to return
+               /// for a search request.
+               /// The search operation will be terminated by the server
+               /// with an LdapException.SIZE_LIMIT_EXCEEDED if the
+               /// number of results exceed the maximum.
+               /// <br><br>
+               /// </param>
+               /// <param name="serverTimeLimit">The maximum time in seconds that the server
+               /// should spend returning search results. This is a
+               /// server-enforced limit.  A value of 0 means
+               /// no time limit.
+               /// <br><br>
+               /// </param>
+               /// <param name="typesOnly">     If true, returns the names but not the values of
+               /// the attributes found.  If false, returns the
+               /// names and values for attributes found.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">           Any controls that apply to the search request.
+               /// or null if none.
+               /// 
+               /// </param>
+               /// <seealso cref="com.novell.ldap.LdapConnection#search">
+               /// </seealso>
+               /// <seealso cref="com.novell.ldap.LdapSearchConstraints">
+               /// </seealso>
+               public LdapSearchRequest(System.String base_Renamed, int scope, RfcFilter filter, System.String[] attrs, int dereference, int maxResults, int serverTimeLimit, bool typesOnly, LdapControl[] cont):base(LdapMessage.SEARCH_REQUEST, new RfcSearchRequest(new RfcLdapDN(base_Renamed), new Asn1Enumerated(scope), new Asn1Enumerated(dereference), new Asn1Integer(maxResults), new Asn1Integer(serverTimeLimit), new Asn1Boolean(typesOnly), filter, new RfcAttributeDescriptionList(attrs)), cont)
+               {
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResult.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResult.cs
new file mode 100755 (executable)
index 0000000..71553fb
--- /dev/null
@@ -0,0 +1,133 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapSearchResult.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Asn1;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary>  Encapsulates a single search result that is in response to an asynchronous
+       /// search operation.
+       /// </summary>
+       /// <seealso cref="LdapConnection#search">
+       /// </seealso>
+       public class LdapSearchResult:LdapMessage
+       {
+               /// <summary> Returns the entry of a server's search response.
+               /// 
+               /// </summary>
+               /// <returns> The LdapEntry associated with this LdapSearchResult
+               /// </returns>
+               virtual public LdapEntry Entry
+               {
+                       get
+                       {
+                               if (entry == null)
+                               {
+                                       LdapAttributeSet attrs = new LdapAttributeSet();
+                                       
+                                       Asn1Sequence attrList = ((RfcSearchResultEntry) message.Response).Attributes;
+                                       
+                                       Asn1Object[] seqArray = attrList.toArray();
+                                       for (int i = 0; i < seqArray.Length; i++)
+                                       {
+                                               Asn1Sequence seq = (Asn1Sequence) seqArray[i];
+                                               LdapAttribute attr = new LdapAttribute(((Asn1OctetString) seq.get_Renamed(0)).stringValue());
+                                               
+                                               Asn1Set set_Renamed = (Asn1Set) seq.get_Renamed(1);
+                                               System.Object[] setArray = set_Renamed.toArray();
+                                               for (int j = 0; j < setArray.Length; j++)
+                                               {
+                                                       attr.addValue(((Asn1OctetString) setArray[j]).byteValue());
+                                               }
+                                               attrs.Add(attr);
+                                       }
+                                       
+                                       entry = new LdapEntry(((RfcSearchResultEntry) message.Response).ObjectName.stringValue(), attrs);
+                               }
+                               return entry;
+                       }
+                       
+               }
+               
+               private LdapEntry entry = null;
+               
+               /// <summary> Constructs an LdapSearchResult object.
+               /// 
+               /// </summary>
+               /// <param name="message">The RfcLdapMessage with a search result.
+               /// </param>
+               /*package*/
+               internal LdapSearchResult(RfcLdapMessage message):base(message)
+               {
+                       return ;
+               }
+               
+               /// <summary> Constructs an LdapSearchResult object from an LdapEntry.
+               /// 
+               /// </summary>
+               /// <param name="entry">the LdapEntry represented by this search result.
+               /// <br><br>
+               /// </param>
+               /// <param name="cont">controls associated with the search result
+               /// </param>
+               public LdapSearchResult(LdapEntry entry, LdapControl[] cont):base()
+               {
+                       if (entry == null)
+                       {
+                               throw new System.ArgumentException("Argument \"entry\" cannot be null");
+                       }
+                       this.entry = entry;
+                       return ;
+               }
+               
+               /// <summary> Return a String representation of this object.
+               /// 
+               /// </summary>
+               /// <returns> a String representing this object.
+               /// </returns>
+               public override System.String ToString()
+               {
+                       System.String str;
+                       if (entry == null)
+                       {
+                               str = base.ToString();
+                       }
+                       else
+                       {
+                               str = entry.ToString();
+                       }
+                       return str;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResultReference.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResultReference.cs
new file mode 100755 (executable)
index 0000000..7511287
--- /dev/null
@@ -0,0 +1,83 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapSearchResultReference.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Asn1;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Encapsulates a continuation reference from an asynchronous search operation.
+       /// 
+       /// </summary>
+       public class LdapSearchResultReference:LdapMessage
+       {
+               /// <summary> Returns any URLs in the object.
+               /// 
+               /// </summary>
+               /// <returns> The URLs.
+               /// </returns>
+               virtual public System.String[] Referrals
+               {
+                       get
+                       {
+                               Asn1Object[] references = ((RfcSearchResultReference) message.Response).toArray();
+                               srefs = new System.String[references.Length];
+                               for (int i = 0; i < references.Length; i++)
+                               {
+                                       srefs[i] = ((Asn1OctetString) (references[i])).stringValue();
+                               }
+                               return (srefs);
+                       }
+                       
+               }
+               
+               private System.String[] srefs;
+               private static System.Object nameLock; // protect agentNum
+               private static int refNum = 0; // Debug, LdapConnection number
+               private System.String name; // String name for debug
+               /*package*/ /// <summary> Constructs an LdapSearchResultReference object.
+               /// 
+               /// </summary>
+               /// <param name="message">The LdapMessage with a search reference.
+               /// </param>
+               internal LdapSearchResultReference(RfcLdapMessage message):base(message)
+               {
+                       return ;
+               }
+               static LdapSearchResultReference()
+               {
+                       nameLock = new System.Object();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResults.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapSearchResults.cs
new file mode 100755 (executable)
index 0000000..70fa5eb
--- /dev/null
@@ -0,0 +1,395 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapSearchResults.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> <p>An LdapSearchResults object is returned from a synchronous search
+       /// operation. It provides access to all results received during the
+       /// operation (entries and exceptions).</p>
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#search">
+       /// </seealso>
+       public class LdapSearchResults
+       {
+               /// <summary> Returns a count of the items in the search result.
+               /// 
+               /// <p>Returns a count of the entries and exceptions remaining in the object.
+               /// If the search was submitted with a batch size greater than zero,
+               /// getCount reports the number of results received so far but not enumerated
+               /// with next().  If batch size equals zero, getCount reports the number of
+               /// items received, since the application thread blocks until all results are
+               /// received.</p>
+               /// 
+               /// </summary>
+               /// <returns> The number of items received but not retrieved by the application
+               /// </returns>
+               virtual public int Count
+               {
+                       get
+                       {
+                               int qCount = queue.MessageAgent.Count;
+                               return entryCount - entryIndex + referenceCount - referenceIndex + qCount;
+                       }
+                       
+               }
+               /// <summary> Returns the latest server controls returned by the server
+               /// in the context of this search request, or null
+               /// if no server controls were returned.
+               /// 
+               /// </summary>
+               /// <returns> The server controls returned with the search request, or null
+               /// if none were returned.
+               /// </returns>
+               virtual public LdapControl[] ResponseControls
+               {
+                       get
+                       {
+                               return controls;
+                       }
+                       
+               }
+               /// <summary> Collects batchSize elements from an LdapSearchQueue message
+               /// queue and places them in a Vector.
+               /// 
+               /// <p>If the last message from the server,
+               /// the result message, contains an error, it will be stored in the Vector
+               /// for nextElement to process. (although it does not increment the search
+               /// result count) All search result entries will be placed in the Vector.
+               /// If a null is returned from getResponse(), it is likely that the search
+               /// was abandoned.</p>
+               /// 
+               /// </summary>
+               /// <returns> true if all search results have been placed in the vector.
+               /// </returns>
+               private bool BatchOfResults
+               {
+                       get
+                       {
+                               LdapMessage msg;
+                               
+                               // <=batchSize so that we can pick up the result-done message
+                               for (int i = 0; i < batchSize; )
+                               {
+                                       try
+                                       {
+                                               if ((msg = queue.getResponse()) != null)
+                                               {
+                                                       // Only save controls if there are some
+                                                       LdapControl[] ctls = msg.Controls;
+                                                       if (ctls != null)
+                                                       {
+                                                               
+                                                               controls = ctls;
+                                                       }
+                                                       
+                                                       if (msg is LdapSearchResult)
+                                                       {
+                                                               // Search Entry
+                                                               System.Object entry = ((LdapSearchResult) msg).Entry;
+                                                               entries.Add(entry);
+                                                               i++;
+                                                               entryCount++;
+                                                       }
+                                                       else if (msg is LdapSearchResultReference)
+                                                       {
+                                                               // Search Ref
+                                                               System.String[] refs = ((LdapSearchResultReference) msg).Referrals;
+                                                               
+                                                               if (cons.ReferralFollowing)
+                                                               {
+//                                                                     referralConn = conn.chaseReferral(queue, cons, msg, refs, 0, true, referralConn);
+                                                               }
+                                                               else
+                                                               {
+                                                                       references.Add(refs);
+                                                                       referenceCount++;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               // LdapResponse
+                                                               LdapResponse resp = (LdapResponse) msg;
+                                                               int resultCode = resp.ResultCode;
+                                                               // Check for an embedded exception
+                                                               if (resp.hasException())
+                                                               {
+                                                                       // Fake it, results in an exception when msg read
+                                                                       resultCode = LdapException.CONNECT_ERROR;
+                                                               }
+                                                               
+                                                               if ((resultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
+                                                               {
+                                                                       // Following referrals
+//                                                                     referralConn = conn.chaseReferral(queue, cons, resp, resp.Referrals, 0, false, referralConn);
+                                                               }
+                                                               else if (resultCode != LdapException.SUCCESS)
+                                                               {
+                                                                       // Results in an exception when message read
+                                                                       entries.Add(resp);
+                                                                       entryCount++;
+                                                               }
+                                                               // We are done only when we have read all messages
+                                                               // including those received from following referrals
+                                                               int[] msgIDs = queue.MessageIDs;
+                                                               if (msgIDs.Length == 0)
+                                                               {
+                                                                       // Release referral exceptions
+//                                                                     conn.releaseReferralConnections(referralConn);
+                                                                       return true; // search completed
+                                                               }
+                                                               else
+                                                               {
+                                                               }
+                                                               continue;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       // We get here if the connection timed out
+                                                       // we have no responses, no message IDs and no exceptions
+                                                       LdapException e = new LdapException(null, LdapException.Ldap_TIMEOUT, (System.String) null);
+                                                       entries.Add(e);
+                                                       break;
+                                               }
+                                       }
+                                       catch (LdapException e)
+                                       {
+                                               // Hand exception off to user
+                                               entries.Add(e);
+                                       }
+                                       continue;
+                               }
+                               return false; // search not completed
+                       }
+                       
+               }
+               
+               private System.Collections.ArrayList entries; // Search entries
+               private int entryCount; // # Search entries in vector
+               private int entryIndex; // Current position in vector
+               private System.Collections.ArrayList references; // Search Result References
+               private int referenceCount; // # Search Result Reference in vector
+               private int referenceIndex; // Current position in vector
+               private int batchSize; // Application specified batch size
+               private bool completed = false; // All entries received
+               private LdapControl[] controls = null; // Last set of controls
+               private LdapSearchQueue queue;
+               private static System.Object nameLock; // protect resultsNum
+               private static int resultsNum = 0; // used for debug
+               private System.String name; // used for debug
+               private LdapConnection conn; // LdapConnection which started search
+               private LdapSearchConstraints cons; // LdapSearchConstraints for search
+               private System.Collections.ArrayList referralConn = null; // Referral Connections
+               
+               /// <summary> Constructs a queue object for search results.
+               /// 
+               /// </summary>
+               /// <param name="conn">The LdapConnection which initiated the search
+               /// <br><br>
+               /// </param>
+               /// <param name="queue">The queue for the search results.
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">The LdapSearchConstraints associated with this search
+               /// </param>
+               /* package */
+               internal LdapSearchResults(LdapConnection conn, LdapSearchQueue queue, LdapSearchConstraints cons)
+               {
+                       // setup entry Vector
+                       this.conn = conn;
+                       this.cons = cons;
+                       int batchSize = cons.BatchSize;
+                       int vectorIncr = (batchSize == 0)?64:0;
+                       entries = new System.Collections.ArrayList((batchSize == 0)?64:batchSize);
+                       entryCount = 0;
+                       entryIndex = 0;
+                       
+                       // setup search reference Vector
+                       references = new System.Collections.ArrayList(5);
+                       referenceCount = 0;
+                       referenceIndex = 0;
+                       
+                       this.queue = queue;
+                       this.batchSize = (batchSize == 0)?System.Int32.MaxValue:batchSize;
+                       
+                       return ;
+               }
+               
+               /// <summary> Reports if there are more search results.
+               /// 
+               /// </summary>
+               /// <returns> true if there are more search results.
+               /// </returns>
+               public virtual bool hasMore()
+               {
+                       bool ret = false;
+                       if ((entryIndex < entryCount) || (referenceIndex < referenceCount))
+                       {
+                               // we have data
+                               ret = true;
+                       }
+                       else if (completed == false)
+                       {
+                               // reload the Vector by getting more results
+                               resetVectors();
+                               ret = (entryIndex < entryCount) || (referenceIndex < referenceCount);
+                       }
+                       return ret;
+               }
+               
+               /*
+               * If both of the vectors are empty, get more data for them.
+               */
+               private void  resetVectors()
+               {
+                       // If we're done, no further checking needed
+                       if (completed)
+                       {
+                               return ;
+                       }
+                       // Checks if we have run out of references
+                       if ((referenceIndex != 0) && (referenceIndex >= referenceCount))
+                       {
+                               SupportClass.SetSize(references, 0);
+                               referenceCount = 0;
+                               referenceIndex = 0;
+                       }
+                       // Checks if we have run out of entries
+                       if ((entryIndex != 0) && (entryIndex >= entryCount))
+                       {
+                               SupportClass.SetSize(entries, 0);
+                               entryCount = 0;
+                               entryIndex = 0;
+                       }
+                       // If no data at all, must reload enumeration
+                       if ((referenceIndex == 0) && (referenceCount == 0) && (entryIndex == 0) && (entryCount == 0))
+                       {
+                               completed = BatchOfResults;
+                       }
+                       return ;
+               }
+               /// <summary> Returns the next result as an LdapEntry.
+               /// 
+               /// <p>If automatic referral following is disabled or if a referral
+               /// was not followed, next() will throw an LdapReferralException
+               /// when the referral is received.</p>
+               /// 
+               /// </summary>
+               /// <returns> The next search result as an LdapEntry.
+               /// 
+               /// </returns>
+               /// <exception cref=""> LdapException A general exception which includes an error
+               /// message and an Ldap error code.
+               /// </exception>
+               /// <exception cref=""> LdapReferralException A referral was received and not
+               /// followed.
+               /// </exception>
+               public virtual LdapEntry next()
+               {
+                       if (completed && (entryIndex >= entryCount) && (referenceIndex >= referenceCount))
+                       {
+                               throw new System.ArgumentOutOfRangeException("LdapSearchResults.next() no more results");
+                       }
+                       // Check if the enumeration is empty and must be reloaded
+                       resetVectors();
+                       
+                       System.Object element = null;
+                       // Check for Search References & deliver to app as they come in
+                       // We only get here if not following referrals/references
+                       if (referenceIndex < referenceCount)
+                       {
+                               System.String[] refs = (System.String[]) (references[referenceIndex++]);
+                               LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERENCE_NOFOLLOW);
+                               rex.setReferrals(refs);
+                               throw rex;
+                       }
+                       else if (entryIndex < entryCount)
+                       {
+                               // Check for Search Entries and the Search Result
+                               element = entries[entryIndex++];
+                               if (element is LdapResponse)
+                               {
+                                       // Search done w/bad status
+                                       if (((LdapResponse) element).hasException())
+                                       {
+                                               
+                                               LdapResponse lr = (LdapResponse) element;
+                                               ReferralInfo ri = lr.ActiveReferral;
+                                               
+                                               if (ri != null)
+                                               {
+                                                       // Error attempting to follow a search continuation reference
+                                                       LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERENCE_ERROR, lr.Exception);
+                                                       rex.setReferrals(ri.ReferralList);
+                                                       rex.FailedReferral = ri.ReferralUrl.ToString();
+                                                       throw rex;
+                                               }
+                                       }
+                                       // Throw an exception if not success
+                                       ((LdapResponse) element).chkResultCode();
+                               }
+                               else if (element is LdapException)
+                               {
+                                       throw (LdapException) element;
+                               }
+                       }
+                       else
+                       {
+                               // If not a Search Entry, Search Result, or search continuation
+                               // we are very confused.
+                               // LdapSearchResults.next(): No entry found & request is not complete
+                               throw new LdapException(ExceptionMessages.REFERRAL_LOCAL, new System.Object[]{"next"}, LdapException.LOCAL_ERROR, (System.String) null);
+                       }
+                       return (LdapEntry) element;
+               }
+               
+               /// <summary> Cancels the search request and clears the message and enumeration.</summary>
+               /*package*/
+               internal virtual void  Abandon()
+               {
+                       // first, remove message ID and timer and any responses in the queue
+                       queue.MessageAgent.AbandonAll();
+                       
+                       // next, clear out enumeration
+                       resetVectors();
+                       completed = true;
+               }
+               static LdapSearchResults()
+               {
+                       nameLock = new System.Object();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUnbindRequest.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUnbindRequest.cs
new file mode 100755 (executable)
index 0000000..a6a752b
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapUnbindRequest.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Represents an Ldap Unbind Request.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#sendRequest">
+       /// </seealso> 
+   /*
+       *       UnbindRequest ::= [APPLICATION 2] NULL
+       */
+       public class LdapUnbindRequest:LdapMessage
+       {
+               /// <summary> Constructs an Ldap Unbind Request.
+               /// 
+               /// </summary>
+               /// <param name="cont">Any controls that apply to the unbind request
+               /// </param>
+               public LdapUnbindRequest(LdapControl[] cont):base(LdapMessage.UNBIND_REQUEST, new RfcUnbindRequest(), cont)
+               {
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUnsolicitedNotificationListener.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUnsolicitedNotificationListener.cs
new file mode 100755 (executable)
index 0000000..9168396
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapUnsolicitedNotificationListener.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// An object that implements this interface can be notified when
+       /// unsolicited messages arrive from the server. A client registers the
+       /// object with LdapConnection.AddUnsolicitedNotificationListener. </p>
+       /// 
+       /// </summary>
+       public interface LdapUnsolicitedNotificationListener
+               {
+                       
+                       /// <summary> The method is called when an unsolicited message arrives from a
+                       /// server, if the object has registered with LdapCo
+                       /// LdapConnection.AddUnsolicitedNotificationListener.
+                       /// 
+                       /// </summary>
+                       /// <param name="msg">    An unsolicited message received from the server.
+                       /// <br><br>
+                       /// </param>
+                       void  messageReceived(LdapExtendedResponse msg);
+               }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUrl.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapUrl.cs
new file mode 100755 (executable)
index 0000000..52a2c3d
--- /dev/null
@@ -0,0 +1,862 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.LdapUrl.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using ArrayEnumeration = Novell.Directory.Ldap.Utilclass.ArrayEnumeration;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> 
+       /// Encapsulates parameters of an Ldap URL query as defined in RFC2255.
+       /// 
+       /// An LdapUrl object can be passed to LdapConnection.search to retrieve
+       /// search results.
+       /// 
+       /// </summary>
+       /// <seealso cref="LdapConnection#search">
+       /// </seealso>
+       public class LdapUrl : System.ICloneable
+       {
+               private void  InitBlock()
+               {
+                       scope = DEFAULT_SCOPE;
+               }
+               /// <summary> Returns an array of attribute names specified in the URL.
+               /// 
+               /// </summary>
+               /// <returns> An array of attribute names in the URL.
+               /// </returns>
+               virtual public System.String[] AttributeArray
+               {
+                       get
+                       {
+                               return attrs;
+                       }
+                       
+               }
+               /// <summary> Returns an enumerator for the attribute names specified in the URL.
+               /// 
+               /// </summary>
+               /// <returns> An enumeration of attribute names.
+               /// </returns>
+               virtual public System.Collections.IEnumerator Attributes
+               {
+                       get
+                       {
+                               return new ArrayEnumeration(attrs);
+                       }
+                       
+               }
+               /// <summary> Returns any Ldap URL extensions specified, or null if none are
+               /// specified. Each extension is a type=value expression. The =value part
+               /// MAY be omitted. The expression MAY be prefixed with '!' if it is
+               /// mandatory for evaluation of the URL.
+               /// 
+               /// </summary>
+               /// <returns> string array of extensions.
+               /// </returns>
+               virtual public System.String[] Extensions
+               {
+                       get
+                       {
+                               return extensions;
+                       }
+                       
+               }
+               /// <summary> Returns the search filter or <code>null</code> if none was specified.
+               /// 
+               /// </summary>
+               /// <returns> The search filter.
+               /// </returns>
+               virtual public System.String Filter
+               {
+                       get
+                       {
+                               return filter;
+                       }
+                       
+               }
+               /// <summary> Returns the name of the Ldap server in the URL.
+               /// 
+               /// </summary>
+               /// <returns> The host name specified in the URL.
+               /// </returns>
+               virtual public System.String Host
+               {
+                       get
+                       {
+                               return host;
+                       }
+                       
+               }
+               /// <summary> Returns the port number of the Ldap server in the URL.
+               /// 
+               /// </summary>
+               /// <returns> The port number in the URL.
+               /// </returns>
+               virtual public int Port
+               {
+                       get
+                       {
+                               if (port == 0)
+                               {
+                                       return LdapConnection.DEFAULT_PORT;
+                               }
+                               return port;
+                       }
+                       
+               }
+               /// <summary> Returns the depth of search. It returns one of the following from
+               /// LdapConnection: SCOPE_BASE, SCOPE_ONE, or SCOPE_SUB.
+               /// 
+               /// </summary>
+               /// <returns> The search scope.
+               /// </returns>
+               virtual public int Scope
+               {
+                       get
+                       {
+                               return scope;
+                       }
+                       
+               }
+               /// <summary> Returns true if the URL is of the type ldaps (Ldap over SSL, a predecessor
+               /// to startTls)
+               /// 
+               /// </summary>
+               /// <returns> whether this is a secure Ldap url or not.
+               /// </returns>
+               virtual public bool Secure
+               {
+                       get
+                       {
+                               return secure;
+                       }
+                       
+               }
+               private static readonly int DEFAULT_SCOPE = LdapConnection.SCOPE_BASE;
+               
+               // Broken out parts of the URL
+               private bool secure = false; // URL scheme ldap/ldaps
+               private bool ipV6 = false; // TCP/IP V6
+               private System.String host = null; // Host
+               private int port = 0; // Port
+               private System.String dn = null; // Base DN
+               private System.String[] attrs = null; // Attributes
+               private System.String filter = null; // Filter
+               private int scope; // Scope
+               private System.String[] extensions = null; // Extensions
+               
+               /// <summary> Constructs a URL object with the specified string as the URL.
+               /// 
+               /// </summary>
+               /// <param name="url">     An Ldap URL string, e.g.
+               /// "ldap://ldap.example.com:80/dc=example,dc=com?cn,
+               /// sn?sub?(objectclass=inetOrgPerson)".
+               /// 
+               /// </param>
+               /// <exception cref=""> MalformedURLException The specified URL cannot be parsed.
+               /// </exception>
+               public LdapUrl(System.String url)
+               {
+                       InitBlock();
+                       parseURL(url);
+                       return ;
+               }
+               
+               
+               /// <summary> Constructs a URL object with the specified host, port, and DN.
+               /// 
+               /// <p>This form is used to create URL references to a particular object
+               /// in the directory.</p>
+               /// 
+               /// </summary>
+               /// <param name="host">    Host identifier of Ldap server, or null for
+               /// "localhost".
+               /// <br><br>
+               /// </param>
+               /// <param name="port">    The port number for Ldap server (use
+               /// LdapConnection.DEFAULT_PORT for default port).
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">      Distinguished name of the base object of the search.
+               /// 
+               /// </param>
+               public LdapUrl(System.String host, int port, System.String dn)
+               {
+                       InitBlock();
+                       this.host = host;
+                       this.port = port;
+                       this.dn = dn;
+                       return ;
+               }
+               
+               /// <summary> Constructs an Ldap URL with all fields explicitly assigned, to
+               /// specify an Ldap search operation.
+               /// 
+               /// </summary>
+               /// <param name="host">    Host identifier of Ldap server, or null for
+               /// "localhost".
+               /// <br><br>
+               /// </param>
+               /// <param name="port">    The port number for Ldap server (use
+               /// LdapConnection.DEFAULT_PORT for default port).
+               /// <br><br>
+               /// </param>
+               /// <param name="dn">      Distinguished name of the base object of the search.
+               /// 
+               /// <br><br>
+               /// </param>
+               /// <param name="attrNames">Names or OIDs of attributes to retrieve.  Passing a
+               /// null array signifies that all user attributes are to be
+               /// retrieved. Passing a value of "*" allows you to specify
+               /// that all user attributes as well as any specified
+               /// operational attributes are to be retrieved.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="scope">   Depth of search (in DN namespace). Use one of
+               /// SCOPE_BASE, SCOPE_ONE, SCOPE_SUB from LdapConnection.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="filter">  The search filter specifying the search criteria.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="extensions"> Extensions provide a mechanism to extend the
+               /// functionality of Ldap URLs. Currently no
+               /// Ldap URL extensions are defined. Each extension
+               /// specification is a type=value expression, and  may
+               /// be <code>null</code> or empty.  The =value part may be
+               /// omitted. The expression may be prefixed with '!' if it
+               /// is mandatory for the evaluation of the URL.
+               /// </param>
+               public LdapUrl(System.String host, int port, System.String dn, System.String[] attrNames, int scope, System.String filter, System.String[] extensions)
+               {
+                       InitBlock();
+                       this.host = host;
+                       this.port = port;
+                       this.dn = dn;
+                       this.attrs = new System.String[attrNames.Length];
+                       attrNames.CopyTo(this.attrs, 0);
+                       this.scope = scope;
+                       this.filter = filter;
+                       this.extensions = new System.String[extensions.Length];
+                       extensions.CopyTo(this.extensions, 0);
+                       return ;
+               }
+               
+               /// <summary> Constructs an Ldap URL with all fields explicitly assigned, including
+               /// isSecure, to specify an Ldap search operation.
+               /// 
+               /// </summary>
+               /// <param name="host">    Host identifier of Ldap server, or null for
+               /// "localhost".
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="port">    The port number for Ldap server (use
+               /// LdapConnection.DEFAULT_PORT for default port).
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="dn">      Distinguished name of the base object of the search.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="attrNames">Names or OIDs of attributes to retrieve.  Passing a
+               /// null array signifies that all user attributes are to be
+               /// retrieved. Passing a value of "*" allows you to specify
+               /// that all user attributes as well as any specified
+               /// operational attributes are to be retrieved.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="scope">   Depth of search (in DN namespace). Use one of
+               /// SCOPE_BASE, SCOPE_ONE, SCOPE_SUB from LdapConnection.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="filter">  The search filter specifying the search criteria.
+               /// from LdapConnection: SCOPE_BASE, SCOPE_ONE, SCOPE_SUB.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="extensions"> Extensions provide a mechanism to extend the
+               /// functionality of Ldap URLs. Currently no
+               /// Ldap URL extensions are defined. Each extension
+               /// specification is a type=value expression, and  may
+               /// be <code>null</code> or empty.  The =value part may be
+               /// omitted. The expression may be prefixed with '!' if it
+               /// is mandatory for the evaluation of the URL.
+               /// <br><br>
+               /// 
+               /// </param>
+               /// <param name="secure">  If true creates an Ldap URL of the ldaps type
+               /// </param>
+               public LdapUrl(System.String host, int port, System.String dn, System.String[] attrNames, int scope, System.String filter, System.String[] extensions, bool secure)
+               {
+                       InitBlock();
+                       this.host = host;
+                       this.port = port;
+                       this.dn = dn;
+                       this.attrs = attrNames;
+                       this.scope = scope;
+                       this.filter = filter;
+                       this.extensions = new System.String[extensions.Length];
+                       extensions.CopyTo(this.extensions, 0);
+                       this.secure = secure;
+                       return ;
+               }
+               
+               /// <summary> Returns a clone of this URL object.
+               /// 
+               /// </summary>
+               /// <returns> clone of this URL object.
+               /// </returns>
+               public System.Object Clone()
+               {
+                       try
+                       {
+                               return base.MemberwiseClone();
+                       }
+                       catch (System.Exception ce)
+                       {
+                               throw new System.SystemException("Internal error, cannot create clone");
+                       }
+               }
+               
+               /// <summary> Decodes a URL-encoded string.
+               /// 
+               /// <p>Any occurences of %HH are decoded to the hex value represented.
+               /// However, this method does NOT decode "+" into " ".
+               /// 
+               /// </summary>
+               /// <param name="URLEncoded">    String to decode.
+               /// 
+               /// </param>
+               /// <returns> The decoded string.
+               /// 
+               /// </returns>
+               /// <exception cref=""> MalformedURLException The URL could not be parsed.
+               /// </exception>
+               public static System.String decode(System.String URLEncoded)
+               {
+                       
+                       
+                       int searchStart = 0;
+                       int fieldStart;
+                       
+                       fieldStart = URLEncoded.IndexOf("%", searchStart);
+                       // Return now if no encoded data
+                       if (fieldStart < 0)
+                       {
+                               return URLEncoded;
+                       }
+                       
+                       // Decode the %HH value and copy to new string buffer
+                       int fieldEnd = 0; // end of previous field
+                       int dataLen = URLEncoded.Length;
+                       
+                       System.Text.StringBuilder decoded = new System.Text.StringBuilder(dataLen);
+                       
+                       while (true)
+                       {
+                               if (fieldStart > (dataLen - 3))
+                               {
+                                       throw new System.UriFormatException("LdapUrl.decode: must be two hex characters following escape character '%'");
+                               }
+                               if (fieldStart < 0)
+                                       fieldStart = dataLen;
+                               // Copy to string buffer from end of last field to start of next
+                               decoded.Append(URLEncoded.Substring(fieldEnd, (fieldStart) - (fieldEnd)));
+                               fieldStart += 1;
+                               if (fieldStart >= dataLen)
+                                       break;
+                               fieldEnd = fieldStart + 2;
+                               try
+                               {
+                                       decoded.Append((char) System.Convert.ToInt32(URLEncoded.Substring(fieldStart, (fieldEnd) - (fieldStart)), 16));
+                               }
+                               catch (System.FormatException ex)
+                               {
+                                       throw new System.UriFormatException("LdapUrl.decode: error converting hex characters to integer \"" + ex.Message + "\"");
+                               }
+                               searchStart = fieldEnd;
+                               if (searchStart == dataLen)
+                                       break;
+                               fieldStart = URLEncoded.IndexOf("%", searchStart);
+                       }
+                       
+                       return (decoded.ToString());
+               }
+               
+               /// <summary> Encodes an arbitrary string using the URL encoding rules.
+               /// 
+               /// <p> Any illegal characters are encoded as %HH. </p>
+               /// 
+               /// </summary>
+               /// <param name="toEncode">    The string to encode.
+               /// 
+               /// </param>
+               /// <returns> The URL-encoded string.
+               /// 
+               /// Comment: An illegal character consists of any non graphical US-ASCII character, Unsafe, or reserved characters.
+               /// </returns>
+               public static System.String encode(System.String toEncode)
+               {
+                       System.Text.StringBuilder buffer = new System.Text.StringBuilder(toEncode.Length); //empty but initial capicity of 'length'
+                       System.String temp;
+                       char currChar;
+                       for (int i = 0; i < toEncode.Length; i++)
+                       {
+                               currChar = toEncode[i];
+                               if ((((int) currChar <= 0x1F) || ((int) currChar == 0x7F) || (((int) currChar >= 0x80) && ((int) currChar <= 0xFF))) || ((currChar == '<') || (currChar == '>') || (currChar == '\"') || (currChar == '#') || (currChar == '%') || (currChar == '{') || (currChar == '}') || (currChar == '|') || (currChar == '\\') || (currChar == '^') || (currChar == '~') || (currChar == '[') || (currChar == '\'')) || ((currChar == ';') || (currChar == '/') || (currChar == '?') || (currChar == ':') || (currChar == '@') || (currChar == '=') || (currChar == '&')))
+                               {
+                                       temp = System.Convert.ToString(currChar, 16);
+                                       if (temp.Length == 1)
+                                               buffer.Append("%0" + temp);
+                                       //if(temp.length()==2) this can only be two or one digit long.
+                                       else
+                                               buffer.Append("%" + System.Convert.ToString(currChar, 16));
+                               }
+                               else
+                                       buffer.Append(currChar);
+                       }
+                       return buffer.ToString();
+               }
+               
+               /// <summary> Returns the base distinguished name encapsulated in the URL.
+               /// 
+               /// </summary>
+               /// <returns> The base distinguished name specified in the URL, or null if none.
+               /// </returns>
+               public virtual System.String getDN()
+               {
+                       return dn;
+               }
+               
+               /// <summary> Sets the base distinguished name encapsulated in the URL.</summary>
+               /* package */
+               internal virtual void  setDN(System.String dn)
+               {
+                       this.dn = dn;
+                       return ;
+               }
+               
+               /// <summary> Returns a valid string representation of this Ldap URL.
+               /// 
+               /// </summary>
+               /// <returns> The string representation of the Ldap URL.
+               /// </returns>
+               public override System.String ToString()
+               {
+                       System.Text.StringBuilder url = new System.Text.StringBuilder(256);
+                       // Scheme
+                       if (secure)
+                       {
+                               url.Append("ldaps://");
+                       }
+                       else
+                       {
+                               url.Append("ldap://");
+                       }
+                       // Host:port/dn
+                       if (ipV6)
+                       {
+                               url.Append("[" + host + "]");
+                       }
+                       else
+                       {
+                               url.Append(host);
+                       }
+                       
+                       // Port not specified
+                       if (port != 0)
+                       {
+                               url.Append(":" + port);
+                       }
+                       
+                       if (((System.Object) dn == null) && (attrs == null) && (scope == DEFAULT_SCOPE) && ((System.Object) filter == null) && (extensions == null))
+                       {
+                               return url.ToString();
+                       }
+                       
+                       url.Append("/");
+                       
+                       if ((System.Object) dn != null)
+                       {
+                               url.Append(dn);
+                       }
+                       
+                       if ((attrs == null) && (scope == DEFAULT_SCOPE) && ((System.Object) filter == null) && (extensions == null))
+                       {
+                               return url.ToString();
+                       }
+                       
+                       // attributes
+                       url.Append("?");
+                       if (attrs != null)
+                       {
+                               //should we check also for attrs != "*"
+                               for (int i = 0; i < attrs.Length; i++)
+                               {
+                                       url.Append(attrs[i]);
+                                       if (i < (attrs.Length - 1))
+                                       {
+                                               url.Append(",");
+                                       }
+                               }
+                       }
+                       
+                       if ((scope == DEFAULT_SCOPE) && ((System.Object) filter == null) && (extensions == null))
+                       {
+                               return url.ToString();
+                       }
+                       
+                       // scope
+                       url.Append("?");
+                       if (scope != DEFAULT_SCOPE)
+                       {
+                               if (scope == LdapConnection.SCOPE_ONE)
+                               {
+                                       url.Append("one");
+                               }
+                               else
+                               {
+                                       url.Append("sub");
+                               }
+                       }
+                       
+                       if (((System.Object) filter == null) && (extensions == null))
+                       {
+                               return url.ToString();
+                       }
+                       
+                       // filter
+                       if ((System.Object) filter == null)
+                       {
+                               url.Append("?");
+                       }
+                       else
+                       {
+                               url.Append("?" + Filter);
+                       }
+                       
+                       if (extensions == null)
+                       {
+                               return url.ToString();
+                       }
+                       
+                       // extensions
+                       url.Append("?");
+                       if (extensions != null)
+                       {
+                               for (int i = 0; i < extensions.Length; i++)
+                               {
+                                       url.Append(extensions[i]);
+                                       if (i < (extensions.Length - 1))
+                                       {
+                                               url.Append(",");
+                                       }
+                               }
+                       }
+                       return url.ToString();
+               }
+               
+               private System.String[] parseList(System.String listStr, char delimiter, int listStart, int listEnd)
+               // end of list + 1
+               {
+                       System.String[] list;
+                       // Check for and empty string
+                       if ((listEnd - listStart) < 1)
+                       {
+                               return null;
+                       }
+                       // First count how many items are specified
+                       int itemStart = listStart;
+                       int itemEnd;
+                       int itemCount = 0;
+                       while (itemStart > 0)
+                       {
+                               // itemStart == 0 if no delimiter found
+                               itemCount += 1;
+                               itemEnd = listStr.IndexOf((System.Char) delimiter, itemStart);
+                               if ((itemEnd > 0) && (itemEnd < listEnd))
+                               {
+                                       itemStart = itemEnd + 1;
+                               }
+                               else
+                               {
+                                       break;
+                               }
+                       }
+                       // Now fill in the array with the attributes
+                       itemStart = listStart;
+                       list = new System.String[itemCount];
+                       itemCount = 0;
+                       while (itemStart > 0)
+                       {
+                               itemEnd = listStr.IndexOf((System.Char) delimiter, itemStart);
+                               if (itemStart <= listEnd)
+                               {
+                                       if (itemEnd < 0)
+                                               itemEnd = listEnd;
+                                       if (itemEnd > listEnd)
+                                               itemEnd = listEnd;
+                                       list[itemCount] = listStr.Substring(itemStart, (itemEnd) - (itemStart));
+                                       itemStart = itemEnd + 1;
+                                       itemCount += 1;
+                               }
+                               else
+                               {
+                                       break;
+                               }
+                       }
+                       return list;
+               }
+               
+               
+               private void  parseURL(System.String url)
+               {
+                       int scanStart = 0;
+                       int scanEnd = url.Length;
+                       
+                       if ((System.Object) url == null)
+                               throw new System.UriFormatException("LdapUrl: URL cannot be null");
+                       
+                       // Check if URL is enclosed by < & >
+                       if (url[scanStart] == '<')
+                       {
+                               if (url[scanEnd - 1] != '>')
+                                       throw new System.UriFormatException("LdapUrl: URL bad enclosure");
+                               scanStart += 1;
+                               scanEnd -= 1;
+                       }
+                       
+                       // Determine the URL scheme and set appropriate default port
+                       if (url.Substring(scanStart, (scanStart + 4) - (scanStart)).ToUpper().Equals("URL:".ToUpper()))
+                       {
+                               scanStart += 4;
+                       }
+                       if (url.Substring(scanStart, (scanStart + 7) - (scanStart)).ToUpper().Equals("ldap://".ToUpper()))
+                       {
+                               scanStart += 7;
+                               port = LdapConnection.DEFAULT_PORT;
+                       }
+                       else if (url.Substring(scanStart, (scanStart + 8) - (scanStart)).ToUpper().Equals("ldaps://".ToUpper()))
+                       {
+                               secure = true;
+                               scanStart += 8;
+                               port = LdapConnection.DEFAULT_SSL_PORT;
+                       }
+                       else
+                       {
+                               throw new System.UriFormatException("LdapUrl: URL scheme is not ldap");
+                       }
+                       
+                       // Find where host:port ends and dn begins
+                       int dnStart = url.IndexOf("/", scanStart);
+                       int hostPortEnd = scanEnd;
+                       bool novell = false;
+                       if (dnStart < 0)
+                       {
+                               /*
+                               * Kludge. check for ldap://111.222.333.444:389??cn=abc,o=company
+                               *
+                               * Check for broken Novell referral format.  The dn is in
+                               * the scope position, but the required slash is missing.
+                               * This is illegal syntax but we need to account for it.
+                               * Fortunately it can't be confused with anything real.
+                               */
+                               dnStart = url.IndexOf("?", scanStart);
+                               if (dnStart > 0)
+                               {
+                                       if (url[dnStart + 1] == '?')
+                                       {
+                                               hostPortEnd = dnStart;
+                                               dnStart += 1;
+                                               novell = true;
+                                       }
+                                       else
+                                       {
+                                               dnStart = - 1;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               hostPortEnd = dnStart;
+                       }
+                       // Check for IPV6 "[ipaddress]:port"
+                       int portStart;
+                       int hostEnd = hostPortEnd;
+                       if (url[scanStart] == '[')
+                       {
+                               hostEnd = url.IndexOf((System.Char) ']', scanStart + 1);
+                               if ((hostEnd >= hostPortEnd) || (hostEnd == - 1))
+                               {
+                                       throw new System.UriFormatException("LdapUrl: \"]\" is missing on IPV6 host name");
+                               }
+                               // Get host w/o the [ & ]
+                               host = url.Substring(scanStart + 1, (hostEnd) - (scanStart + 1));
+                               portStart = url.IndexOf(":", hostEnd);
+                               if ((portStart < hostPortEnd) && (portStart != - 1))
+                               {
+                                       // port is specified
+                                       port = System.Int32.Parse(url.Substring(portStart + 1, (hostPortEnd) - (portStart + 1)));
+                               }
+                               else
+                               {
+                               }
+                       }
+                       else
+                       {
+                               portStart = url.IndexOf(":", scanStart);
+                               // Isolate the host and port
+                               if ((portStart < 0) || (portStart > hostPortEnd))
+                               {
+                                       // no port is specified, we keep the default
+                                       host = url.Substring(scanStart, (hostPortEnd) - (scanStart));
+                               }
+                               else
+                               {
+                                       // port specified in URL
+                                       host = url.Substring(scanStart, (portStart) - (scanStart));
+                                       port = System.Int32.Parse(url.Substring(portStart + 1, (hostPortEnd) - (portStart + 1)));
+                               }
+                       }
+                       
+                       scanStart = hostPortEnd + 1;
+                       if ((scanStart >= scanEnd) || (dnStart < 0))
+                               return ;
+                       
+                       // Parse out the base dn
+                       scanStart = dnStart + 1;
+                       
+                       int attrsStart = url.IndexOf((System.Char) '?', scanStart);
+                       if (attrsStart < 0)
+                       {
+                               dn = url.Substring(scanStart, (scanEnd) - (scanStart));
+                       }
+                       else
+                       {
+                               dn = url.Substring(scanStart, (attrsStart) - (scanStart));
+                       }
+                       
+                       scanStart = attrsStart + 1;
+                       // Wierd novell syntax can have nothing beyond the dn
+                       if ((scanStart >= scanEnd) || (attrsStart < 0) || novell)
+                               return ;
+                       
+                       // Parse out the attributes
+                       int scopeStart = url.IndexOf((System.Char) '?', scanStart);
+                       if (scopeStart < 0)
+                               scopeStart = scanEnd - 1;
+                       attrs = parseList(url, ',', attrsStart + 1, scopeStart);
+                       
+                       scanStart = scopeStart + 1;
+                       if (scanStart >= scanEnd)
+                               return ;
+                       
+                       // Parse out the scope
+                       int filterStart = url.IndexOf((System.Char) '?', scanStart);
+                       System.String scopeStr;
+                       if (filterStart < 0)
+                       {
+                               scopeStr = url.Substring(scanStart, (scanEnd) - (scanStart));
+                       }
+                       else
+                       {
+                               scopeStr = url.Substring(scanStart, (filterStart) - (scanStart));
+                       }
+                       if (scopeStr.ToUpper().Equals("".ToUpper()))
+                       {
+                               scope = LdapConnection.SCOPE_BASE;
+                       }
+                       else if (scopeStr.ToUpper().Equals("base".ToUpper()))
+                       {
+                               scope = LdapConnection.SCOPE_BASE;
+                       }
+                       else if (scopeStr.ToUpper().Equals("one".ToUpper()))
+                       {
+                               scope = LdapConnection.SCOPE_ONE;
+                       }
+                       else if (scopeStr.ToUpper().Equals("sub".ToUpper()))
+                       {
+                               scope = LdapConnection.SCOPE_SUB;
+                       }
+                       else
+                       {
+                               throw new System.UriFormatException("LdapUrl: URL invalid scope");
+                       }
+                       
+                       
+                       scanStart = filterStart + 1;
+                       if ((scanStart >= scanEnd) || (filterStart < 0))
+                               return ;
+                       
+                       // Parse out the filter
+                       scanStart = filterStart + 1;
+                       
+                       System.String filterStr;
+                       int extStart = url.IndexOf((System.Char) '?', scanStart);
+                       if (extStart < 0)
+                       {
+                               filterStr = url.Substring(scanStart, (scanEnd) - (scanStart));
+                       }
+                       else
+                       {
+                               filterStr = url.Substring(scanStart, (extStart) - (scanStart));
+                       }
+                       
+                       if (!filterStr.Equals(""))
+                       {
+                               filter = filterStr; // Only modify if not the default filter
+                       }
+                       
+                       
+                       scanStart = extStart + 1;
+                       if ((scanStart >= scanEnd) || (extStart < 0))
+                               return ;
+                       
+                       // Parse out the extensions
+                       int end = url.IndexOf((System.Char) '?', scanStart);
+                       if (end > 0)
+                               throw new System.UriFormatException("LdapUrl: URL has too many ? fields");
+                       extensions = parseList(url, ',', scanStart, scanEnd);
+                       
+                       return ;
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Message.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Message.cs
new file mode 100755 (executable)
index 0000000..48c9740
--- /dev/null
@@ -0,0 +1,605 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.Message.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Rfc2251;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> Encapsulates an Ldap message, its state, and its replies.</summary>
+       /* package */
+       class Message
+       {
+               private void  InitBlock()
+               {
+                       replies = new MessageVector(5, 5);
+               }
+               /// <summary> Get number of messages queued.
+               /// Don't count the last message containing result code.
+               /// </summary>
+               virtual internal int Count
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               int size = replies.Count;
+                               if (complete)
+                               {
+                                       return (size > 0?(size - 1):size);
+                               }
+                               else
+                               {
+                                       return size;
+                               }
+                       }
+                       
+               }
+
+               /// <summary> sets the agent for this message</summary>
+               virtual internal MessageAgent Agent
+               {
+                       /* package */
+                       
+                       set
+                       {
+                               this.agent = value;
+                               return ;
+                       }
+                       
+               }
+
+               /// <summary> Returns true if replies are queued
+               /// 
+               /// </summary>
+               /// <returns> false if no replies are queued, otherwise true
+               /// </returns>
+               /* package */
+               internal virtual bool hasReplies()
+               {
+                       if (replies == null)
+                       {
+                               // abandoned request
+                               return false;
+                       }
+                       return (replies.Count > 0);
+               }
+
+               virtual internal int MessageType
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               if (msg == null)
+                               {
+                                       return - 1;
+                               }
+                               return msg.Type;
+                       }
+                       
+               }
+
+               virtual internal int MessageID
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return msgId;
+                       }
+                       
+               }
+
+               /// <summary> gets the operation complete status for this message
+               /// 
+               /// </summary>
+               /// <returns> the true if the operation is complete, i.e.
+               /// the LdapResult has been received.
+               /// </returns>
+               virtual internal bool Complete
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return complete;
+                       }
+                       
+               }
+
+               /// <summary> Gets the next reply from the reply queue or waits until one is there
+               /// 
+               /// </summary>
+               /// <returns> the next reply message on the reply queue or null
+               /// </returns>
+               /* package */
+               internal virtual System.Object waitForReply()
+               {
+                       if (replies == null)
+                       {
+                               return null;
+                       }
+                       // sync on message so don't confuse with timer thread
+                       lock (replies)
+                       {
+                               System.Object msg = null;
+                               while (waitForReply_Renamed_Field)
+                               {
+                                       if ((replies.Count == 0))
+                                       {
+                                               try
+                                               {
+                                                       System.Threading.Monitor.Wait(replies);
+                                               }
+                                               catch (System.Threading.ThreadInterruptedException ir)
+                                               {
+                                                       ; // do nothing
+                                               }
+                                               if (waitForReply_Renamed_Field)
+                                               {
+                                                       continue;
+                                               }
+                                               else
+                                               {
+                                                       break;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               System.Object temp_object;
+                                               temp_object = replies[0];
+                                               replies.RemoveAt(0);
+                                               msg = temp_object; // Atomic get and remove
+                                       }
+                                       if ((complete || !acceptReplies) && (replies.Count == 0))
+                                       {
+                                               // Remove msg from connection queue when last reply read
+                                               conn.removeMessage(this);
+                                       }
+                                       else
+                                       {
+                                       }
+                                       return msg;
+                               }
+                               return null;
+                       }
+               }
+               
+
+               /// <summary> Gets the next reply from the reply queue if one exists
+               /// 
+               /// </summary>
+               /// <returns> the next reply message on the reply queue or null if none
+               /// </returns>
+               virtual internal System.Object Reply
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               System.Object msg;
+                               if (replies == null)
+                               {
+                                       return null;
+                               }
+                               lock (replies)
+                               {
+                                       // Test and remove must be atomic
+                                       if ((replies.Count == 0))
+                                       {
+                                               return null; // No data
+                                       }
+                                       System.Object temp_object;
+                                       temp_object = replies[0];
+                                       replies.RemoveAt(0);
+                                       msg = temp_object; // Atomic get and remove
+                               }
+                               if ((conn != null) && (complete || !acceptReplies) && (replies.Count == 0))
+                               {
+                                       // Remove msg from connection queue when last reply read
+                                       conn.removeMessage(this);
+                               }
+                               return msg;
+                       }
+                       
+               }
+
+               /// <summary> Returns true if replies are accepted for this request.
+               /// 
+               /// </summary>
+               /// <returns> false if replies are no longer accepted for this request
+               /// </returns>
+               /* package */
+               internal virtual bool acceptsReplies()
+               {
+                       return acceptReplies;
+               }
+
+               /// <summary> gets the LdapMessage request associated with this message
+               /// 
+               /// </summary>
+               /// <returns> the LdapMessage request associated with this message
+               /// </returns>
+               virtual internal LdapMessage Request
+               {
+                       /*package*/
+                       
+                       get
+                       {
+                               return msg;
+                       }
+                       
+               }
+
+
+               virtual internal bool BindRequest
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return (bindprops != null);
+                       }
+                       
+               }
+
+
+               /// <summary> gets the MessageAgent associated with this message
+               /// 
+               /// </summary>
+               /// <returns> the MessageAgent associated with this message
+               /// </returns>
+               virtual internal MessageAgent MessageAgent
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return agent;
+                       }
+                       
+               }
+
+               private LdapMessage msg; // msg request sent to server
+               private Connection conn; // Connection object where msg sent
+               private MessageAgent agent; // MessageAgent handling this request
+               private LdapMessageQueue queue; // Application message queue
+               private int mslimit; // client time limit in milliseconds
+               private SupportClass.ThreadClass timer = null; // Timeout thread
+               // Note: MessageVector is synchronized
+               private MessageVector replies; // place to store replies
+               private int msgId; // message ID of this request
+               private bool acceptReplies = true; // false if no longer accepting replies
+               private bool waitForReply_Renamed_Field = true; // true if wait for reply
+               private bool complete = false; // true LdapResult received
+               private System.String name; // String name used for Debug
+               private BindProperties bindprops; // Bind properties if a bind request
+               
+               internal Message(LdapMessage msg, int mslimit, Connection conn, MessageAgent agent, LdapMessageQueue queue, BindProperties bindprops)
+               {
+                       InitBlock();
+                       this.msg = msg;
+                       this.conn = conn;
+                       this.agent = agent;
+                       this.queue = queue;
+                       this.mslimit = mslimit;
+                       this.msgId = msg.MessageID;
+                       this.bindprops = bindprops;
+                       return ;
+               }
+
+               internal void  sendMessage()
+               {
+                       conn.writeMessage(this);
+                       // Start the timer thread
+                       if (mslimit != 0)
+                       {
+                               // Don't start the timer thread for abandon or Unbind
+                               switch (msg.Type)
+                               {
+                                       
+                                       case LdapMessage.ABANDON_REQUEST: 
+                                       case LdapMessage.UNBIND_REQUEST: 
+                                               mslimit = 0;
+                                               break;
+                                       
+                                       default: 
+                                               timer = new Timeout(this, mslimit, this);
+                                               timer.IsBackground = true; // If this is the last thread running, allow exit.
+                                               timer.Start();
+                                               break;
+                                       
+                               }
+                       }
+                       return ;
+               }
+
+               internal virtual void  Abandon(LdapConstraints cons, InterThreadException informUserEx)
+               {
+                       if (!waitForReply_Renamed_Field)
+                       {
+                               return ;
+                       }
+                       acceptReplies = false; // don't listen to anyone
+                       waitForReply_Renamed_Field = false; // don't let sleeping threads lie
+                       if (!complete)
+                       {
+                               try
+                               {
+                                       // If a bind, release bind semaphore & wake up waiting threads
+                                       // Must do before writing abandon message, otherwise deadlock
+                                       if (bindprops != null)
+                                       {
+                                               int id;
+                                               if (conn.BindSemIdClear)
+                                               {
+                                                       // Semaphore id for normal operations
+                                                       id = msgId;
+                                               }
+                                               else
+                                               {
+                                                       // Semaphore id for sasl bind
+                                                       id = conn.BindSemId;
+                                                       conn.clearBindSemId();
+                                               }
+                                               conn.freeWriteSemaphore(id);
+                                       }
+                                       
+                                       // Create the abandon message, but don't track it.
+                                       LdapControl[] cont = null;
+                                       if (cons != null)
+                                       {
+                                               cont = cons.getControls();
+                                       }
+                                       LdapMessage msg = new LdapAbandonRequest(msgId, cont);
+                                       // Send abandon message to server
+                                       conn.writeMessage(msg);
+                               }
+                               catch (LdapException ex)
+                               {
+                                       ; // do nothing
+                               }
+                               // If not informing user, remove message from agent
+                               if (informUserEx == null)
+                               {
+                                       agent.Abandon(msgId, null);
+                               }
+                               conn.removeMessage(this);
+                       }
+                       // Get rid of all replies queued
+                       if (informUserEx != null)
+                       {
+                               replies.Add(new LdapResponse(informUserEx, conn.ActiveReferral));
+                               stopTimer();
+                               // wake up waiting threads to receive exception
+                               sleepersAwake();
+                               // Message will get cleaned up when last response removed from queue
+                       }
+                       else
+                       {
+                               // Wake up any waiting threads, so they can terminate.
+                               // If informing the user, we wake sleepers after
+                               // caller queues dummy response with error status
+                               sleepersAwake();
+                               cleanup();
+                       }
+                       return ;
+               }
+
+               private void  cleanup()
+               {
+                       stopTimer(); // Make sure timer stopped
+                       try
+                       {
+                               acceptReplies = false;
+                               if (conn != null)
+                               {
+                                       conn.removeMessage(this);
+                               }
+                               // Empty out any accumuluated replies
+                               if (replies != null)
+                               {
+                                       while (!(replies.Count == 0))
+                                       {
+                                               System.Object temp_object;
+                                               temp_object = replies[0];
+                                               replies.RemoveAt(0);
+                                               System.Object generatedAux = temp_object;
+                                       }
+                               }
+                       }
+                       catch (System.Exception ex)
+                       {
+                               // nothing
+                       }
+                       // Let GC clean up this stuff, leave name in case finalized is called
+                       conn = null;
+                       msg = null;
+                       // agent = null;  // leave this reference
+                       queue = null;
+                       //replies = null; //leave this since we use it as a semaphore
+                       bindprops = null;
+                       return ;
+               }
+               
+               ~Message()
+               {
+                       cleanup();
+                       return ;
+               }
+
+
+               internal virtual void  putReply(RfcLdapMessage message)
+               {
+                       if (!acceptReplies)
+                       {
+                               return ;
+                       }
+                       replies.Add(message);
+                       message.RequestingMessage = msg; // Save request message info
+                       switch (message.Type)
+                       {
+                               
+                               case LdapMessage.SEARCH_RESPONSE: 
+                               case LdapMessage.SEARCH_RESULT_REFERENCE: 
+                                       break;
+                               
+                               default: 
+                                       int res;
+                                       stopTimer();
+                                       // Accept no more results for this message
+                                       // Leave on connection queue so we can abandon if necessary
+                                       acceptReplies = false;
+                                       complete = true;
+                                       if (bindprops != null)
+                                       {
+                                               res = ((RfcResponse) message.Response).getResultCode().intValue();
+                                               if (res == LdapException.SASL_BIND_IN_PROGRESS)
+                                               {
+                                               }
+                                               else
+                                               {
+                                                       // We either have success or failure on the bind
+                                                       if (res == LdapException.SUCCESS)
+                                                       {
+                                                               // Set bind properties into connection object
+                                                               conn.BindProperties = bindprops;
+                                                       }
+                                                       else
+                                                       {
+                                                       }
+                                                       // If not a sasl bind in-progress, release the bind
+                                                       // semaphore and wake up all waiting threads
+                                                       int id;
+                                                       if (conn.BindSemIdClear)
+                                                       {
+                                                               // Semaphore id for normal operations
+                                                               id = msgId;
+                                                       }
+                                                       else
+                                                       {
+                                                               // Semaphore id for sasl bind
+                                                               id = conn.BindSemId;
+                                                               conn.clearBindSemId();
+                                                       }
+                                                       conn.freeWriteSemaphore(id);
+                                               }
+                                       }
+                                       break;
+                               
+                       }
+                       // wake up waiting threads
+                       sleepersAwake();
+                       return ;
+               }
+               
+               /// <summary> stops the timeout timer from running</summary>
+               /* package */
+               internal virtual void  stopTimer()
+               {
+                       // If timer thread started, stop it
+                       if (timer != null)
+                       {
+                               timer.Interrupt();
+                       }
+                       return ;
+               }
+
+               /// <summary> Notifies all waiting threads</summary>
+               private void  sleepersAwake()
+               {
+                       // Notify any thread waiting for this message id
+                       lock (replies)
+                       {
+                               System.Threading.Monitor.Pulse(replies);
+                       }
+                       // Notify a thread waiting for any message id
+                       agent.sleepersAwake(false);
+                       return ;
+               }
+
+               /// <summary> Timer class to provide timing for messages.  Only called
+               /// if time to wait is non zero.
+               /// </summary>
+               private sealed class Timeout:SupportClass.ThreadClass
+               {
+                       private void  InitBlock(Message enclosingInstance)
+                       {
+                               this.enclosingInstance = enclosingInstance;
+                       }
+                       private Message enclosingInstance;
+                       public Message Enclosing_Instance
+                       {
+                               get
+                               {
+                                       return enclosingInstance;
+                               }
+                               
+                       }
+                       private int timeToWait = 0;
+                       private Message message;
+                       
+                       /* package */
+                       internal Timeout(Message enclosingInstance, int interval, Message msg):base()
+                       {
+                               InitBlock(enclosingInstance);
+                               timeToWait = interval;
+                               message = msg;
+                               return ;
+                       }
+                       
+                       /// <summary> The timeout thread.  If it wakes from the sleep, future input
+                       /// is stopped and the request is timed out.
+                       /// </summary>
+                       override public void  Run()
+                       {
+                               try
+                               {
+                                       System.Threading.Thread.Sleep(new System.TimeSpan(10000 * timeToWait));
+                                       message.acceptReplies = false;
+                                       // Note: Abandon clears the bind semaphore after failed bind.
+                                       message.Abandon(null, new InterThreadException("Client request timed out", null, LdapException.Ldap_TIMEOUT, null, message));
+                               }
+                               catch (System.Threading.ThreadInterruptedException ie)
+                               {
+                                       // the timer was stopped, do nothing
+                               }
+                               return ;
+                       }
+               }
+
+               /// <summary> sets the agent for this message</summary>
+
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/MessageAgent.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/MessageAgent.cs
new file mode 100755 (executable)
index 0000000..48731f2
--- /dev/null
@@ -0,0 +1,436 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.MessageAgent.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+using Novell.Directory.Ldap.Utilclass;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /* package */
+       class MessageAgent
+       {
+               private void  InitBlock()
+               {
+                       messages = new MessageVector(5, 5);
+               }
+               /// <summary> empty and return all messages owned by this agent
+               /// 
+               /// 
+               /// </summary>
+               virtual internal System.Object[] MessageArray
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               return messages.ObjectArray;
+                       }
+                       
+               }
+               /// <summary> Get a list of message ids controlled by this agent
+               /// 
+               /// </summary>
+               /// <returns> an array of integers representing the message ids
+               /// </returns>
+               virtual internal int[] MessageIDs
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               int size = messages.Count;
+                               int[] ids = new int[size];
+                               Message info;
+                               
+                               for (int i = 0; i < size; i++)
+                               {
+                                       info = (Message) messages[i];
+                                       ids[i] = info.MessageID;
+                               }
+                               return ids;
+                       }
+                       
+               }
+               /// <summary> Get the maessage agent number for debugging
+               /// 
+               /// </summary>
+               /// <returns> the agent number
+               /// </returns>
+               virtual internal System.String AgentName
+               {
+                       /*packge*/
+                       
+                       get
+                       {
+                               return name;
+                       }
+                       
+               }
+               /// <summary> Get a count of all messages queued</summary>
+               virtual internal int Count
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               int count = 0;
+                               System.Object[] msgs = messages.ToArray();
+                               for (int i = 0; i < msgs.Length; i++)
+                               {
+                                       Message m = (Message) msgs[i];
+                                       count += m.Count;
+                               }
+                               return count;
+                       }
+                       
+               }
+               private MessageVector messages;
+               private int indexLastRead = 0;
+               private static System.Object nameLock; // protect agentNum
+               private static int agentNum = 0; // Debug, agent number
+               private System.String name; // String name for debug
+               
+               /* package */
+               internal MessageAgent()
+               {
+                       InitBlock();
+                       // Get a unique agent id for debug
+               }
+               
+               /// <summary> merges two message agents
+               /// 
+               /// </summary>
+               /// <param name="fromAgent">the agent to be merged into this one
+               /// </param>
+               /* package */
+               internal void  merge(MessageAgent fromAgent)
+               {
+                       System.Object[] msgs = fromAgent.MessageArray;
+                       for (int i = 0; i < msgs.Length; i++)
+                       {
+                               messages.Add(msgs[i]);
+                               ((Message) (msgs[i])).Agent = this;
+                       }
+                       lock (messages)
+                       {
+                               if (msgs.Length > 1)
+                               {
+                                       System.Threading.Monitor.PulseAll(messages); // wake all threads waiting for messages
+                               }
+                               else if (msgs.Length == 1)
+                               {
+                                       System.Threading.Monitor.Pulse(messages); // only wake one thread
+                               }
+                       }
+                       return ;
+               }
+               
+               
+               /// <summary> Wakes up any threads waiting for messages in the message agent
+               /// 
+               /// </summary>
+               /* package */
+               internal void  sleepersAwake(bool all)
+               {
+                       lock (messages)
+                       {
+                               if (all)
+                                       System.Threading.Monitor.PulseAll(messages);
+                               else
+                                       System.Threading.Monitor.Pulse(messages);
+                       }
+                       return ;
+               }
+               
+               /// <summary> Returns true if any responses are queued for any of the agent's messages
+               /// 
+               /// return false if no responses are queued, otherwise true
+               /// </summary>
+               /* package */
+               internal bool isResponseReceived()
+               {
+                       int size = messages.Count;
+                       int next = indexLastRead + 1;
+                       Message info;
+                       for (int i = 0; i < size; i++)
+                       {
+                               if (next == size)
+                               {
+                                       next = 0;
+                               }
+                               info = (Message) messages[next];
+                               if (info.hasReplies())
+                               {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               
+               /// <summary> Returns true if any responses are queued for the specified msgId
+               /// 
+               /// return false if no responses are queued, otherwise true
+               /// </summary>
+               /* package */
+               internal bool isResponseReceived(int msgId)
+               {
+                       try
+                       {
+                               Message info = messages.findMessageById(msgId);
+                               return info.hasReplies();
+                       }
+                       catch (System.FieldAccessException ex)
+                       {
+                               return false;
+                       }
+               }
+               
+               /// <summary> Abandon the request associated with MsgId
+               /// 
+               /// </summary>
+               /// <param name="msgId">the message id to abandon
+               /// <br><br>
+               /// </param>
+               /// <param name="cons">constraints associated with this request
+               /// </param>
+               /* package */
+               internal void  Abandon(int msgId, LdapConstraints cons)
+               //, boolean informUser)
+               {
+                       Message info = null;
+                       try
+                       {
+                               // Send abandon request and remove from connection list
+                               info = messages.findMessageById(msgId);
+                               SupportClass.VectorRemoveElement(messages, info); // This message is now dead
+                               info.Abandon(cons, null);
+                               
+                               return ;
+                       }
+                       catch (System.FieldAccessException ex)
+                       {
+                       }
+                       return ;
+               }
+               
+               /// <summary> Abandon all requests on this MessageAgent</summary>
+               /* package */
+               internal void  AbandonAll()
+               {
+                       int size = messages.Count;
+                       Message info;
+                       
+                       for (int i = 0; i < size; i++)
+                       {
+                               info = (Message) messages[i];
+                               // Message complete and no more replies, remove from id list
+                               SupportClass.VectorRemoveElement(messages, info);
+                               info.Abandon(null, null);
+                       }
+                       return ;
+               }
+               
+               /// <summary> Indicates whether a specific operation is complete
+               /// 
+               /// </summary>
+               /// <returns> true if a specific operation is complete
+               /// </returns>
+               /* package */
+               internal bool isComplete(int msgid)
+               {
+                       try
+                       {
+                               Message info = messages.findMessageById(msgid);
+                               if (!info.Complete)
+                               {
+                                       return false;
+                               }
+                       }
+                       catch (System.FieldAccessException ex)
+                       {
+                               ; // return true, if no message, it must be complete
+                       }
+                       return true;
+               }
+               
+               /// <summary> Returns the Message object for a given messageID
+               /// 
+               /// </summary>
+               /// <param name="msgid">the message ID.
+               /// </param>
+               /* package */
+               internal Message getMessage(int msgid)
+               {
+                       return messages.findMessageById(msgid);
+               }
+               
+               /// <summary> Send a request to the server.  A Message class is created
+               /// for the specified request which causes the message to be sent.
+               /// The request is added to the list of messages being managed by
+               /// this agent.
+               /// 
+               /// </summary>
+               /// <param name="conn">the connection that identifies the server.
+               /// <br><br>
+               /// </param>
+               /// <param name="msg">the LdapMessage to send
+               /// <br><br>
+               /// </param>
+               /// <param name="timeOut">the interval to wait for the message to complete or
+               /// <code>null</code> if infinite.
+               /// </param>
+               /// <param name="queue">the LdapMessageQueue associated with this request.
+               /// </param>
+               /* package */
+               internal void  sendMessage(Connection conn, LdapMessage msg, int timeOut, LdapMessageQueue queue, BindProperties bindProps)
+               {
+                       // creating a messageInfo causes the message to be sent
+                       // and a timer to be started if needed.
+                       Message message = new Message(msg, timeOut, conn, this, queue, bindProps);
+                       messages.Add(message);
+                       message.sendMessage(); // Now send message to server
+                       return ;
+               }
+               
+               /// <summary> Returns a response queued, or waits if none queued
+               /// 
+               /// </summary>
+               /* package */
+//             internal System.Object getLdapMessage(System.Int32 msgId)
+               internal System.Object getLdapMessage(System.Int32 msgId)
+               {
+                       return (getLdapMessage(new Integer32(msgId)));
+               }
+
+               internal System.Object getLdapMessage(Integer32 msgId)
+               {
+                       System.Object rfcMsg;
+                       // If no messages for this agent, just return null
+                       if (messages.Count == 0)
+                       {
+                               return null;
+                       }
+                       if ( msgId != null)
+                       {
+                               // Request messages for a specific ID
+                               try
+                               {
+                                       // Get message for this ID
+//                                     Message info = messages.findMessageById(msgId);
+                                       Message info = messages.findMessageById(msgId.intValue);
+                                       rfcMsg = info.waitForReply(); // blocks for a response
+                                       if (!info.acceptsReplies() && !info.hasReplies())
+                                       {
+                                               // Message complete and no more replies, remove from id list
+                                               SupportClass.VectorRemoveElement(messages, info);
+                                               info.Abandon(null, null); // Get rid of resources
+                                       }
+                                       else
+                                       {
+                                       }
+                                       return rfcMsg;
+                               }
+                               catch (System.FieldAccessException ex)
+                               {
+                                       // no such message id
+                                       return null;
+                               }
+                       }
+                       else
+                       {
+                               // A msgId was NOT specified, any message will do
+                               lock (messages)
+                               {
+                                       while (true)
+                                       {
+                                               int next = indexLastRead + 1;
+                                               Message info;
+                                               for (int i = 0; i < messages.Count; i++)
+                                               {
+                                                       if (next >= messages.Count)
+                                                       {
+                                                               next = 0;
+                                                       }
+                                                       info = (Message) messages[next];
+                                                       indexLastRead = next++;
+                                                       rfcMsg = info.Reply;
+                                                       // Check this request is complete
+                                                       if (!info.acceptsReplies() && !info.hasReplies())
+                                                       {
+                                                               // Message complete & no more replies, remove from id list
+                                                               SupportClass.VectorRemoveElement(messages, info); // remove from list
+                                                               info.Abandon(null, null); // Get rid of resources
+                                                               // Start loop at next message that is now moved
+                                                               // to the current position in the Vector.
+                                                               i -= 1;
+                                                       }
+                                                       if (rfcMsg != null)
+                                                       {
+                                                               // We got a reply
+                                                               return rfcMsg;
+                                                       }
+                                                       else
+                                                       {
+                                                               // We found no reply here
+                                                       }
+                                               } // end for loop */
+                                               // Messages can be removed in this loop, we we must
+                                               // check if any messages left for this agent
+                                               if (messages.Count == 0)
+                                               {
+                                                       return null;
+                                               }
+                                               
+                                               // No data, wait for something to come in.
+                                               try
+                                               {
+                                                       System.Threading.Monitor.Wait(messages);
+                                               }
+                                               catch (System.Threading.ThreadInterruptedException ex)
+                                               {
+                                               }
+                                       } /* end while */
+                               } /* end synchronized */
+                       }
+               }
+               
+               /// <summary> Debug code to print messages in message vector</summary>
+               private void  debugDisplayMessages()
+               {
+                       return ;
+               }
+               static MessageAgent()
+               {
+                       nameLock = new System.Object();
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/MessageVector.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/MessageVector.cs
new file mode 100755 (executable)
index 0000000..cdbdb8a
--- /dev/null
@@ -0,0 +1,109 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.MessageVector.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+using System;
+
+namespace Novell.Directory.Ldap
+{
+       
+       /// <summary> The <code>MessageVector</code> class implements additional semantics
+       /// to Vector needed for handling messages.
+       /// </summary>
+       /* package */
+       class MessageVector:System.Collections.ArrayList
+       {
+               /// <summary>Returns an array containing all of the elements in this MessageVector.
+               /// The elements returned are in the same order in the array as in the
+               /// Vector.  The contents of the vector are cleared.
+               /// 
+               /// </summary>
+               /// <returns> the array containing all of the elements.
+               /// </returns>
+               virtual internal System.Object[] ObjectArray
+               {
+                       /* package */
+                       
+                       get
+                       {
+                               lock (this)
+                               {
+                                       System.Object[] results = new System.Object[Count];
+                                       Array.Copy((System.Array) ToArray(), 0, (System.Array) results, 0, Count);
+                                       for (int i = 0; i < Count; i++)
+                                       {
+                                               ToArray()[i] = null;
+                                       }
+//                                     Count = 0;
+                                       return results;
+                               }
+                       }
+                       
+               }
+               /* package */
+               internal MessageVector(int cap, int incr):base(cap)
+               {
+                       return ;
+               }
+               
+               /// <summary> Finds the Message object with the given MsgID, and returns the Message
+               /// object. It finds the object and returns it in an atomic operation.
+               /// 
+               /// </summary>
+               /// <param name="msgId">The msgId of the Message object to return
+               /// 
+               /// </param>
+               /// <returns> The Message object corresponding to this MsgId.
+               /// 
+               /// @throws NoSuchFieldException when no object with the corresponding
+               /// value for the MsgId field can be found.
+               /// </returns>
+               /* package */
+               internal Message findMessageById(int msgId)
+               {
+                       lock (this)
+                       {
+                               Message msg = null;
+                               for (int i = 0; i < Count; i++)
+                               {
+                                       if ((msg = (Message) ToArray()[i]) == null)
+                                       {
+                                               throw new System.FieldAccessException();
+                                       }
+                                       if (msg.MessageID == msgId)
+                                       {
+                                               return msg;
+                                       }
+                               }
+                               throw new System.FieldAccessException();
+                       }
+               }
+       }
+}
diff --git a/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/SupportClass.cs b/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/SupportClass.cs
new file mode 100755 (executable)
index 0000000..3bbd8f9
--- /dev/null
@@ -0,0 +1,2090 @@
+/******************************************************************************
+* The MIT License
+* Copyright (c) 2003 Novell Inc.  www.novell.com
+* 
+* Permission is hereby granted, free of charge, to any person obtaining  a copy
+* of this software and associated documentation files (the Software), to deal
+* in the Software without restriction, including  without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+* copies of the Software, and to  permit persons to whom the Software is 
+* furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in 
+* all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*******************************************************************************/
+//
+// Novell.Directory.Ldap.SupportClass.cs
+//
+// Author:
+//   Sunil Kumar (Sunilk@novell.com)
+//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+//
+
+// Support classes replicate the functionality of the original code, but in some cases they are 
+// substantially different architecturally. Although every effort is made to preserve the 
+// original architecture of the application in the converted project, the user should be aware that 
+// the primary goal of these support classes is to replicate functionality, and that at times 
+// the architecture of the resulting solution may differ somewhat.
+//
+
+using System;
+
+       /// <summary>
+       /// This interface should be implemented by any class whose instances are intended 
+       /// to be executed by a thread.
+       /// </summary>
+       public interface IThreadRunnable
+       {
+               /// <summary>
+               /// This method has to be implemented in order that starting of the thread causes the object's 
+               /// run method to be called in that separately executing thread.
+               /// </summary>
+               void Run();
+       }
+
+
+       public class Integer32 : System.Object
+       {
+               private System.Int32 _wintv;
+
+               public Integer32(System.Int32 ival)    
+               {
+                       _wintv=ival;
+               }
+       
+               public System.Int32 intValue
+               {       
+                       get
+                       {
+                               return _wintv;
+                       }
+                       set
+                       {
+                               _wintv=value;
+                       }
+               }
+       }
+               
+       /// <summary>
+       /// Contains conversion support elements such as classes, interfaces and static methods.
+       /// </summary>
+       public class SupportClass
+       {
+               /// <summary>
+               /// Receives a byte array and returns it transformed in an sbyte array
+               /// </summary>
+               /// <param name="byteArray">Byte array to process</param>
+               /// <returns>The transformed array</returns>
+               [CLSCompliantAttribute(false)]
+               public static sbyte[] ToSByteArray(byte[] byteArray)
+               {
+                       sbyte[] sbyteArray = new sbyte[byteArray.Length];
+                       for(int index=0; index < byteArray.Length; index++)
+                               sbyteArray[index] = (sbyte) byteArray[index];
+                       return sbyteArray;
+               }
+               /*******************************/
+               /// <summary>
+               /// Converts an array of sbytes to an array of bytes
+               /// </summary>
+               /// <param name="sbyteArray">The array of sbytes to be converted</param>
+               /// <returns>The new array of bytes</returns>
+               [CLSCompliantAttribute(false)]
+               public static byte[] ToByteArray(sbyte[] sbyteArray)
+               {
+                       byte[] byteArray = new byte[sbyteArray.Length];
+                       for(int index=0; index < sbyteArray.Length; index++)
+                               byteArray[index] = (byte) sbyteArray[index];
+                       return byteArray;
+               }
+
+               /// <summary>
+               /// Converts a string to an array of bytes
+               /// </summary>
+               /// <param name="sourceString">The string to be converted</param>
+               /// <returns>The new array of bytes</returns>
+               public static byte[] ToByteArray(string sourceString)
+               {
+                       byte[] byteArray = new byte[sourceString.Length];
+                       for (int index=0; index < sourceString.Length; index++)
+                               byteArray[index] = (byte) sourceString[index];
+                       return byteArray;
+               }
+
+               /// <summary>
+               /// Converts a array of object-type instances to a byte-type array.
+               /// </summary>
+               /// <param name="tempObjectArray">Array to convert.</param>
+               /// <returns>An array of byte type elements.</returns>
+               public static byte[] ToByteArray(object[] tempObjectArray)
+               {
+                       byte[] byteArray = new byte[tempObjectArray.Length];
+                       for (int index = 0; index < tempObjectArray.Length; index++)
+                               byteArray[index] = (byte)tempObjectArray[index];
+                       return byteArray;
+               }
+
+
+               /*******************************/
+               /// <summary>Reads a number of characters from the current source Stream and writes the data to the target array at the specified index.</summary>
+               /// <param name="sourceStream">The source Stream to read from.</param>
+               /// <param name="target">Contains the array of characteres read from the source Stream.</param>
+               /// <param name="start">The starting index of the target array.</param>
+               /// <param name="count">The maximum number of characters to read from the source Stream.</param>
+               /// <returns>The number of characters read. The number will be less than or equal to count depending on the data available in the source Stream. Returns -1 if the end of the stream is reached.</returns>
+               [CLSCompliantAttribute(false)]
+               public static System.Int32 ReadInput(System.IO.Stream sourceStream, ref sbyte[] target, int start, int count)
+               {
+                       // Returns 0 bytes if not enough space in target
+                       if (target.Length == 0)
+                               return 0;
+
+                       byte[] receiver = new byte[target.Length];
+                       int bytesRead   = sourceStream.Read(receiver, start, count);
+
+                       // Returns -1 if EOF
+                       if (bytesRead == 0)     
+                               return -1;
+                
+                       for(int i = start; i < start + bytesRead; i++)
+                               target[i] = (sbyte)receiver[i];
+                
+                       return bytesRead;
+               }
+
+               /// <summary>Reads a number of characters from the current source TextReader and writes the data to the target array at the specified index.</summary>
+               /// <param name="sourceTextReader">The source TextReader to read from</param>
+               /// <param name="target">Contains the array of characteres read from the source TextReader.</param>
+               /// <param name="start">The starting index of the target array.</param>
+               /// <param name="count">The maximum number of characters to read from the source TextReader.</param>
+               /// <returns>The number of characters read. The number will be less than or equal to count depending on the data available in the source TextReader. Returns -1 if the end of the stream is reached.</returns>
+               [CLSCompliantAttribute(false)]
+               public static System.Int32 ReadInput(System.IO.TextReader sourceTextReader, ref sbyte[] target, int start, int count)
+               {
+                       // Returns 0 bytes if not enough space in target
+                       if (target.Length == 0) return 0;
+
+                       char[] charArray = new char[target.Length];
+                       int bytesRead = sourceTextReader.Read(charArray, start, count);
+
+                       // Returns -1 if EOF
+                       if (bytesRead == 0) return -1;
+
+                       for(int index=start; index<start+bytesRead; index++)
+                               target[index] = (sbyte)charArray[index];
+
+                       return bytesRead;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// This method returns the literal value received
+               /// </summary>
+               /// <param name="literal">The literal to return</param>
+               /// <returns>The received value</returns>
+               public static long Identity(long literal)
+               {
+                       return literal;
+               }
+
+               /// <summary>
+               /// This method returns the literal value received
+               /// </summary>
+               /// <param name="literal">The literal to return</param>
+               /// <returns>The received value</returns>
+               [CLSCompliantAttribute(false)]
+               public static ulong Identity(ulong literal)
+               {
+                       return literal;
+               }
+
+               /// <summary>
+               /// This method returns the literal value received
+               /// </summary>
+               /// <param name="literal">The literal to return</param>
+               /// <returns>The received value</returns>
+               public static float Identity(float literal)
+               {
+                       return literal;
+               }
+
+               /// <summary>
+               /// This method returns the literal value received
+               /// </summary>
+               /// <param name="literal">The literal to return</param>
+               /// <returns>The received value</returns>
+               public static double Identity(double literal)
+               {
+                       return literal;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// The class performs token processing from strings
+               /// </summary>
+               public class Tokenizer
+               {
+                       //Element list identified
+                       private System.Collections.ArrayList elements;
+                       //Source string to use
+                       private string source;
+                       //The tokenizer uses the default delimiter set: the space character, the tab character, the newline character, and the carriage-return character
+                       private string delimiters = " \t\n\r";          
+
+                       /// <summary>
+                       /// Initializes a new class instance with a specified string to process
+                       /// </summary>
+                       /// <param name="source">String to tokenize</param>
+                       public Tokenizer(string source)
+                       {                       
+                               this.elements = new System.Collections.ArrayList();
+                               this.elements.AddRange(source.Split(this.delimiters.ToCharArray()));
+                               this.RemoveEmptyStrings();
+                               this.source = source;
+                       }
+
+                       /// <summary>
+                       /// Initializes a new class instance with a specified string to process
+                       /// and the specified token delimiters to use
+                       /// </summary>
+                       /// <param name="source">String to tokenize</param>
+                       /// <param name="delimiters">String containing the delimiters</param>
+                       public Tokenizer(string source, string delimiters)
+                       {
+                               this.elements = new System.Collections.ArrayList();
+                               this.delimiters = delimiters;
+                               this.elements.AddRange(source.Split(this.delimiters.ToCharArray()));
+                               this.RemoveEmptyStrings();
+                               this.source = source;
+                       }
+
+                       /// <summary>
+                       /// Current token count for the source string
+                       /// </summary>
+                       public int Count
+                       {
+                               get
+                               {
+                                       return (this.elements.Count);
+                               }
+                       }
+
+                       /// <summary>
+                       /// Determines if there are more tokens to return from the source string
+                       /// </summary>
+                       /// <returns>True or false, depending if there are more tokens</returns>
+                       public bool HasMoreTokens()
+                       {
+                               return (this.elements.Count > 0);                       
+                       }
+
+                       /// <summary>
+                       /// Returns the next token from the token list
+                       /// </summary>
+                       /// <returns>The string value of the token</returns>
+                       public string NextToken()
+                       {                       
+                               string result;
+                               if (source == "") throw new System.Exception();
+                               else
+                               {
+                                       this.elements = new System.Collections.ArrayList();
+                                       this.elements.AddRange(this.source.Split(delimiters.ToCharArray()));
+                                       RemoveEmptyStrings();           
+                                       result = (string) this.elements[0];
+                                       this.elements.RemoveAt(0);                              
+                                       this.source = this.source.Remove(this.source.IndexOf(result),result.Length);
+                                       this.source = this.source.TrimStart(this.delimiters.ToCharArray());
+                                       return result;                                  
+                               }                       
+                       }
+
+                       /// <summary>
+                       /// Returns the next token from the source string, using the provided
+                       /// token delimiters
+                       /// </summary>
+                       /// <param name="delimiters">String containing the delimiters to use</param>
+                       /// <returns>The string value of the token</returns>
+                       public string NextToken(string delimiters)
+                       {
+                               this.delimiters = delimiters;
+                               return NextToken();
+                       }
+
+                       /// <summary>
+                       /// Removes all empty strings from the token list
+                       /// </summary>
+                       private void RemoveEmptyStrings()
+                       {
+                               for (int index=0; index < this.elements.Count; index++)
+                                       if ((string)this.elements[index]== "")
+                                       {
+                                               this.elements.RemoveAt(index);
+                                               index--;
+                                       }
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Provides support for DateFormat
+               /// </summary>
+               public class DateTimeFormatManager
+               {
+                       static public DateTimeFormatHashTable manager = new DateTimeFormatHashTable();
+
+                       /// <summary>
+                       /// Hashtable class to provide functionality for dateformat properties
+                       /// </summary>
+                       public class DateTimeFormatHashTable :System.Collections.Hashtable 
+                       {
+                               /// <summary>
+                               /// Sets the format for datetime.
+                               /// </summary>
+                               /// <param name="format">DateTimeFormat instance to set the pattern</param>
+                               /// <param name="newPattern">A string with the pattern format</param>
+                               public void SetDateFormatPattern(System.Globalization.DateTimeFormatInfo format, System.String newPattern)
+                               {
+                                       if (this[format] != null)
+                                               ((DateTimeFormatProperties) this[format]).DateFormatPattern = newPattern;
+                                       else
+                                       {
+                                               DateTimeFormatProperties tempProps = new DateTimeFormatProperties();
+                                               tempProps.DateFormatPattern  = newPattern;
+                                               Add(format, tempProps);
+                                       }
+                               }
+
+                               /// <summary>
+                               /// Gets the current format pattern of the DateTimeFormat instance
+                               /// </summary>
+                               /// <param name="format">The DateTimeFormat instance which the value will be obtained</param>
+                               /// <returns>The string representing the current datetimeformat pattern</returns>
+                               public string GetDateFormatPattern(System.Globalization.DateTimeFormatInfo format)
+                               {
+                                       if (this[format] == null)
+                                               return "d-MMM-yy";
+                                       else
+                                               return ((DateTimeFormatProperties) this[format]).DateFormatPattern;
+                               }
+               
+                               /// <summary>
+                               /// Sets the datetimeformat pattern to the giving format
+                               /// </summary>
+                               /// <param name="format">The datetimeformat instance to set</param>
+                               /// <param name="newPattern">The new datetimeformat pattern</param>
+                               public void SetTimeFormatPattern(System.Globalization.DateTimeFormatInfo format, System.String newPattern)
+                               {
+                                       if (this[format] != null)
+                                               ((DateTimeFormatProperties) this[format]).TimeFormatPattern = newPattern;
+                                       else
+                                       {
+                                               DateTimeFormatProperties tempProps = new DateTimeFormatProperties();
+                                               tempProps.TimeFormatPattern  = newPattern;
+                                               Add(format, tempProps);
+                                       }
+                               }
+
+                               /// <summary>
+                               /// Gets the current format pattern of the DateTimeFormat instance
+                               /// </summary>
+                               /// <param name="format">The DateTimeFormat instance which the value will be obtained</param>
+                               /// <returns>The string representing the current datetimeformat pattern</returns>
+                               public string GetTimeFormatPattern(System.Globalization.DateTimeFormatInfo format)
+                               {
+                                       if (this[format] == null)
+                                               return "h:mm:ss tt";
+                                       else
+                                               return ((DateTimeFormatProperties) this[format]).TimeFormatPattern;
+                               }
+
+                               /// <summary>
+                               /// Internal class to provides the DateFormat and TimeFormat pattern properties on .NET
+                               /// </summary>
+                               class DateTimeFormatProperties
+                               {
+                                       public string DateFormatPattern = "d-MMM-yy";
+                                       public string TimeFormatPattern = "h:mm:ss tt";
+                               }
+                       }       
+               }
+               /*******************************/
+               /// <summary>
+               /// Gets the DateTimeFormat instance and date instance to obtain the date with the format passed
+               /// </summary>
+               /// <param name="format">The DateTimeFormat to obtain the time and date pattern</param>
+               /// <param name="date">The date instance used to get the date</param>
+               /// <returns>A string representing the date with the time and date patterns</returns>
+               public static string FormatDateTime(System.Globalization.DateTimeFormatInfo format, System.DateTime date)
+               {
+                       string timePattern = DateTimeFormatManager.manager.GetTimeFormatPattern(format);
+                       string datePattern = DateTimeFormatManager.manager.GetDateFormatPattern(format);
+                       return date.ToString(datePattern + " " + timePattern, format);            
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Adds a new key-and-value pair into the hash table
+               /// </summary>
+               /// <param name="collection">The collection to work with</param>
+               /// <param name="key">Key used to obtain the value</param>
+               /// <param name="newValue">Value asociated with the key</param>
+               /// <returns>The old element associated with the key</returns>
+               public static System.Object PutElement(System.Collections.IDictionary collection, System.Object key, System.Object newValue)
+               {
+                       System.Object element = collection[key];
+                       collection[key] = newValue;
+                       return element;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// This class contains static methods to manage arrays.
+               /// </summary>
+               public class ArrayListSupport
+               {
+                       /// <summary>
+                       /// Obtains an array containing all the elements of the collection. 
+                       /// </summary>
+                       /// <param name="collection">The collection from wich to obtain the elements.</param>
+                       /// <param name="objects">The array containing all the elements of the collection.</param>
+                       /// <returns>The array containing all the elements of the collection.</returns>
+                       public static System.Object[] ToArray(System.Collections.ArrayList collection, System.Object[] objects)
+                       {       
+                               int index = 0;
+                               System.Collections.IEnumerator tempEnumerator = collection.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       objects[index++] = tempEnumerator.Current;
+                               return objects;
+                       }
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// Removes the first occurrence of an specific object from an ArrayList instance.
+               /// </summary>
+               /// <param name="arrayList">The ArrayList instance</param>
+               /// <param name="element">The element to remove</param>
+               /// <returns>True if item is found in the ArrayList; otherwise, false</returns>  
+               public static System.Boolean VectorRemoveElement(System.Collections.ArrayList arrayList, System.Object element)
+               {
+                       System.Boolean containsItem = arrayList.Contains(element);
+                       arrayList.Remove(element);
+                       return containsItem;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Support class used to handle threads
+               /// </summary>
+               public class ThreadClass : IThreadRunnable
+               {
+                       /// <summary>
+                       /// The instance of System.Threading.Thread
+                       /// </summary>
+                       private System.Threading.Thread threadField;
+             
+                       /// <summary>
+                       /// Initializes a new instance of the ThreadClass class
+                       /// </summary>
+                       public ThreadClass()
+                       {
+                               threadField = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
+                       }
+        
+                       /// <summary>
+                       /// Initializes a new instance of the Thread class.
+                       /// </summary>
+                       /// <param name="Name">The name of the thread</param>
+                       public ThreadClass(string Name)
+                       {
+                               threadField = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
+                               this.Name = Name;
+                       }
+             
+                       /// <summary>
+                       /// Initializes a new instance of the Thread class.
+                       /// </summary>
+                       /// <param name="Start">A ThreadStart delegate that references the methods to be invoked when this thread begins executing</param>
+                       public ThreadClass(System.Threading.ThreadStart Start)
+                       {
+                               threadField = new System.Threading.Thread(Start);
+                       }
+        
+                       /// <summary>
+                       /// Initializes a new instance of the Thread class.
+                       /// </summary>
+                       /// <param name="Start">A ThreadStart delegate that references the methods to be invoked when this thread begins executing</param>
+                       /// <param name="Name">The name of the thread</param>
+                       public ThreadClass(System.Threading.ThreadStart Start, string Name)
+                       {
+                               threadField = new System.Threading.Thread(Start);
+                               this.Name = Name;
+                       }
+             
+                       /// <summary>
+                       /// This method has no functionality unless the method is overridden
+                       /// </summary>
+                       public virtual void Run()
+                       {
+                       }
+             
+                       /// <summary>
+                       /// Causes the operating system to change the state of the current thread instance to ThreadState.Running
+                       /// </summary>
+                       public virtual void Start()
+                       {
+                               threadField.Start();
+                       }
+             
+                       /// <summary>
+                       /// Interrupts a thread that is in the WaitSleepJoin thread state
+                       /// </summary>
+                       public virtual void Interrupt()
+                       {
+                               threadField.Interrupt();
+                       }
+             
+                       /// <summary>
+                       /// Gets the current thread instance
+                       /// </summary>
+                       public System.Threading.Thread Instance
+                       {
+                               get
+                               {
+                                       return threadField;
+                               }
+                               set
+                               {
+                                       threadField = value;
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Gets or sets the name of the thread
+                       /// </summary>
+                       public System.String Name
+                       {
+                               get
+                               {
+                                       return threadField.Name;
+                               }
+                               set
+                               {
+                                       if (threadField.Name == null)
+                                               threadField.Name = value; 
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Gets or sets a value indicating the scheduling priority of a thread
+                       /// </summary>
+                       public System.Threading.ThreadPriority Priority
+                       {
+                               get
+                               {
+                                       return threadField.Priority;
+                               }
+                               set
+                               {
+                                       threadField.Priority = value;
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Gets a value indicating the execution status of the current thread
+                       /// </summary>
+                       public bool IsAlive
+                       {
+                               get
+                               {
+                                       return threadField.IsAlive;
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Gets or sets a value indicating whether or not a thread is a background thread.
+                       /// </summary>
+                       public bool IsBackground
+                       {
+                               get
+                               {
+                                       return threadField.IsBackground;
+                               } 
+                               set
+                               {
+                                       threadField.IsBackground = value;
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Blocks the calling thread until a thread terminates
+                       /// </summary>
+                       public void Join()
+                       {
+                               threadField.Join();
+                       }
+             
+                       /// <summary>
+                       /// Blocks the calling thread until a thread terminates or the specified time elapses
+                       /// </summary>
+                       /// <param name="MiliSeconds">Time of wait in milliseconds</param>
+                       public void Join(long MiliSeconds)
+                       {
+                               lock(this)
+                               {
+                                       threadField.Join(new System.TimeSpan(MiliSeconds * 10000));
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Blocks the calling thread until a thread terminates or the specified time elapses
+                       /// </summary>
+                       /// <param name="MiliSeconds">Time of wait in milliseconds</param>
+                       /// <param name="NanoSeconds">Time of wait in nanoseconds</param>
+                       public void Join(long MiliSeconds, int NanoSeconds)
+                       {
+                               lock(this)
+                               {
+                                       threadField.Join(new System.TimeSpan(MiliSeconds * 10000 + NanoSeconds * 100));
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Resumes a thread that has been suspended
+                       /// </summary>
+                       public void Resume()
+                       {
+                               threadField.Resume();
+                       }
+             
+                       /// <summary>
+                       /// Raises a ThreadAbortException in the thread on which it is invoked, 
+                       /// to begin the process of terminating the thread. Calling this method 
+                       /// usually terminates the thread
+                       /// </summary>
+                       public void Abort()
+                       {
+                               threadField.Abort();
+                       }
+             
+                       /// <summary>
+                       /// Raises a ThreadAbortException in the thread on which it is invoked, 
+                       /// to begin the process of terminating the thread while also providing
+                       /// exception information about the thread termination. 
+                       /// Calling this method usually terminates the thread.
+                       /// </summary>
+                       /// <param name="stateInfo">An object that contains application-specific information, such as state, which can be used by the thread being aborted</param>
+                       public void Abort(System.Object stateInfo)
+                       {
+                               lock(this)
+                               {
+                                       threadField.Abort(stateInfo);
+                               }
+                       }
+             
+                       /// <summary>
+                       /// Suspends the thread, if the thread is already suspended it has no effect
+                       /// </summary>
+                       public void Suspend()
+                       {
+                               threadField.Suspend();
+                       }
+             
+                       /// <summary>
+                       /// Obtain a String that represents the current Object
+                       /// </summary>
+                       /// <returns>A String that represents the current Object</returns>
+                       public override System.String ToString()
+                       {
+                               return "Thread[" + Name + "," + Priority.ToString() + "," + "" + "]";
+                       }
+            
+                       /// <summary>
+                       /// Gets the currently running thread
+                       /// </summary>
+                       /// <returns>The currently running thread</returns>
+                       public static ThreadClass Current()
+                       {
+                               ThreadClass CurrentThread = new ThreadClass();
+                               CurrentThread.Instance = System.Threading.Thread.CurrentThread;
+                               return CurrentThread;
+                       }
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// This class contains different methods to manage Collections.
+               /// </summary>
+               public class CollectionSupport : System.Collections.CollectionBase
+               {
+                       /// <summary>
+                       /// Creates an instance of the Collection by using an inherited constructor.
+                       /// </summary>
+                       public CollectionSupport() : base()
+                       {                       
+                       }
+
+                       /// <summary>
+                       /// Adds an specified element to the collection.
+                       /// </summary>
+                       /// <param name="element">The element to be added.</param>
+                       /// <returns>Returns true if the element was successfuly added. Otherwise returns false.</returns>
+                       public virtual bool Add(System.Object element)
+                       {
+                               return (this.List.Add(element) != -1);
+                       }       
+
+                       /// <summary>
+                       /// Adds all the elements contained in the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               if (collection!=null)
+                               {
+                                       System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(collection).GetEnumerator();
+                                       while (tempEnumerator.MoveNext())
+                                       {
+                                               if (tempEnumerator.Current != null)
+                                                       result = this.Add(tempEnumerator.Current);
+                                       }
+                               }
+                               return result;
+                       }
+
+
+                       /// <summary>
+                       /// Adds all the elements contained in the specified support class collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(CollectionSupport collection)
+                       {
+                               return this.AddAll((System.Collections.ICollection)collection);
+                       }
+
+                       /// <summary>
+                       /// Verifies if the specified element is contained into the collection. 
+                       /// </summary>
+                       /// <param name="element"> The element that will be verified.</param>
+                       /// <returns>Returns true if the element is contained in the collection. Otherwise returns false.</returns>
+                       public virtual bool Contains(System.Object element)
+                       {
+                               return this.List.Contains(element);
+                       }
+
+                       /// <summary>
+                       /// Verifies if all the elements of the specified collection are contained into the current collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be verified.</param>
+                       /// <returns>Returns true if all the elements are contained in the collection. Otherwise returns false.</returns>
+                       public virtual bool ContainsAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(collection).GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       if (!(result = this.Contains(tempEnumerator.Current)))
+                                               break;
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Verifies if all the elements of the specified collection are contained into the current collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be verified.</param>
+                       /// <returns>Returns true if all the elements are contained in the collection. Otherwise returns false.</returns>
+                       public virtual bool ContainsAll(CollectionSupport collection)
+                       {
+                               return this.ContainsAll((System.Collections.ICollection) collection);
+                       }
+
+                       /// <summary>
+                       /// Verifies if the collection is empty.
+                       /// </summary>
+                       /// <returns>Returns true if the collection is empty. Otherwise returns false.</returns>
+                       public virtual bool IsEmpty()
+                       {
+                               return (this.Count == 0);
+                       }
+
+                       /// <summary>
+                       /// Removes an specified element from the collection.
+                       /// </summary>
+                       /// <param name="element">The element to be removed.</param>
+                       /// <returns>Returns true if the element was successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool Remove(System.Object element)
+                       {
+                               bool result = false;
+                               if (this.Contains(element))
+                               {
+                                       this.List.Remove(element);
+                                       result = true;
+                               }
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Removes all the elements contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be removed.</param>
+                       /// <returns>Returns true if all the elements were successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool RemoveAll(System.Collections.ICollection collection)
+                       { 
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(collection).GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                               {
+                                       if (this.Contains(tempEnumerator.Current))
+                                               result = this.Remove(tempEnumerator.Current);
+                               }
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Removes all the elements contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be removed.</param>
+                       /// <returns>Returns true if all the elements were successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool RemoveAll(CollectionSupport collection)
+                       { 
+                               return this.RemoveAll((System.Collections.ICollection) collection);
+                       }
+
+                       /// <summary>
+                       /// Removes all the elements that aren't contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to verify the elements that will be retained.</param>
+                       /// <returns>Returns true if all the elements were successfully removed. Otherwise returns false.</returns>
+                       public virtual bool RetainAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               CollectionSupport tempCollection = new CollectionSupport();
+                               tempCollection.AddAll(collection);
+                               while (tempEnumerator.MoveNext())
+                                       if (!tempCollection.Contains(tempEnumerator.Current))
+                                       {
+                                               result = this.Remove(tempEnumerator.Current);
+                                       
+                                               if (result == true)
+                                               {
+                                                       tempEnumerator = this.GetEnumerator();
+                                               }
+                                       }
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Removes all the elements that aren't contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to verify the elements that will be retained.</param>
+                       /// <returns>Returns true if all the elements were successfully removed. Otherwise returns false.</returns>
+                       public virtual bool RetainAll(CollectionSupport collection)
+                       {
+                               return this.RetainAll((System.Collections.ICollection) collection);
+                       }
+
+                       /// <summary>
+                       /// Obtains an array containing all the elements of the collection.
+                       /// </summary>
+                       /// <returns>The array containing all the elements of the collection</returns>
+                       public virtual System.Object[] ToArray()
+                       {       
+                               int index = 0;
+                               System.Object[] objects = new System.Object[this.Count];
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       objects[index++] = tempEnumerator.Current;
+                               return objects;
+                       }
+
+                       /// <summary>
+                       /// Obtains an array containing all the elements of the collection.
+                       /// </summary>
+                       /// <param name="objects">The array into which the elements of the collection will be stored.</param>
+                       /// <returns>The array containing all the elements of the collection.</returns>
+                       public virtual System.Object[] ToArray(System.Object[] objects)
+                       {       
+                               int index = 0;
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       objects[index++] = tempEnumerator.Current;
+                               return objects;
+                       }
+
+                       /// <summary>
+                       /// Creates a CollectionSupport object with the contents specified in array.
+                       /// </summary>
+                       /// <param name="array">The array containing the elements used to populate the new CollectionSupport object.</param>
+                       /// <returns>A CollectionSupport object populated with the contents of array.</returns>
+                       public static CollectionSupport ToCollectionSupport(System.Object[] array)
+                       {
+                               CollectionSupport tempCollectionSupport = new CollectionSupport();             
+                               tempCollectionSupport.AddAll(array);
+                               return tempCollectionSupport;
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// This class contains different methods to manage list collections.
+               /// </summary>
+               public class ListCollectionSupport : System.Collections.ArrayList
+               {
+                       /// <summary>
+                       /// Creates a new instance of the class ListCollectionSupport.
+                       /// </summary>
+                       public ListCollectionSupport() : base()
+                       {
+                       }
+                       /// <summary>
+                       /// Creates a new instance of the class ListCollectionSupport.
+                       /// </summary>
+                       /// <param name="collection">The collection to insert into the new object.</param>
+                       public ListCollectionSupport(System.Collections.ICollection collection) : base(collection)
+                       {
+                       }
+
+                       /// <summary>
+                       /// Creates a new instance of the class ListCollectionSupport with the specified capacity.
+                       /// </summary>
+                       /// <param name="capacity">The capacity of the new array.</param>
+                       public ListCollectionSupport(int capacity) : base(capacity)
+                       {
+                       }
+
+                       /// <summary>
+                       /// Adds an object to the end of the List.
+                       /// </summary>          
+                       /// <param name="valueToInsert">The value to insert in the array list.</param>
+                       /// <returns>Returns true after adding the value.</returns>
+                       public virtual bool Add(System.Object valueToInsert)
+                       {
+                               base.Insert(this.Count, valueToInsert);
+                               return true;
+                       }
+
+                       /// <summary>
+                       /// Adds all the elements contained into the specified collection, starting at the specified position.
+                       /// </summary>
+                       /// <param name="index">Position at which to add the first element from the specified collection.</param>
+                       /// <param name="list">The list used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(int index, System.Collections.IList list)
+                       {
+                               bool result = false;
+                               if (list!=null)
+                               {
+                                       System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(list).GetEnumerator();
+                                       int tempIndex = index;
+                                       while (tempEnumerator.MoveNext())
+                                       {
+                                               base.Insert(tempIndex++, tempEnumerator.Current);
+                                               result = true;
+                                       }
+                               }
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Adds all the elements contained in the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(System.Collections.IList collection)
+                       {
+                               return this.AddAll(this.Count,collection);
+                       }
+
+                       /// <summary>
+                       /// Adds all the elements contained in the specified support class collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(CollectionSupport collection)
+                       {
+                               return this.AddAll(this.Count,collection);
+                       }
+
+                       /// <summary>
+                       /// Adds all the elements contained into the specified support class collection, starting at the specified position.
+                       /// </summary>
+                       /// <param name="index">Position at which to add the first element from the specified collection.</param>
+                       /// <param name="list">The list used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(int index, CollectionSupport collection)
+                       {
+                               return this.AddAll(index,(System.Collections.IList)collection);
+                       }
+               
+                       /// <summary>
+                       /// Creates a copy of the ListCollectionSupport.
+                       /// </summary>
+                       /// <returns> A copy of the ListCollectionSupport.</returns>
+                       public virtual System.Object ListCollectionClone()
+                       {
+                               return MemberwiseClone();
+                       }
+
+
+                       /// <summary>
+                       /// Returns an iterator of the collection.
+                       /// </summary>
+                       /// <returns>An IEnumerator.</returns>
+                       public virtual System.Collections.IEnumerator ListIterator()
+                       {
+                               return base.GetEnumerator();
+                       }
+
+                       /// <summary>
+                       /// Removes all the elements contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be removed.</param>
+                       /// <returns>Returns true if all the elements were successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool RemoveAll(System.Collections.ICollection collection)
+                       { 
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(collection).GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                               {
+                                       result = true;
+                                       if (base.Contains(tempEnumerator.Current))
+                                               base.Remove(tempEnumerator.Current);
+                               }
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Removes all the elements contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be removed.</param>
+                       /// <returns>Returns true if all the elements were successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool RemoveAll(CollectionSupport collection)
+                       { 
+                               return this.RemoveAll((System.Collections.ICollection) collection);
+                       }               
+
+                       /// <summary>
+                       /// Removes the value in the specified index from the list.
+                       /// </summary>          
+                       /// <param name="index">The index of the value to remove.</param>
+                       /// <returns>Returns the value removed.</returns>
+                       public virtual System.Object RemoveElement(int index)
+                       {
+                               System.Object objectRemoved = this[index];
+                               this.RemoveAt(index);
+                               return objectRemoved;
+                       }
+
+                       /// <summary>
+                       /// Removes an specified element from the collection.
+                       /// </summary>
+                       /// <param name="element">The element to be removed.</param>
+                       /// <returns>Returns true if the element was successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool RemoveElement(System.Object element)
+                       {
+
+                               bool result = false;
+                               if (this.Contains(element))
+                               {
+                                       base.Remove(element);
+                                       result = true;
+                               }
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Removes the first value from an array list.
+                       /// </summary>          
+                       /// <returns>Returns the value removed.</returns>
+                       public virtual System.Object RemoveFirst()
+                       {
+                               System.Object objectRemoved = this[0];
+                               this.RemoveAt(0);
+                               return objectRemoved;
+                       }
+
+                       /// <summary>
+                       /// Removes the last value from an array list.
+                       /// </summary>
+                       /// <returns>Returns the value removed.</returns>
+                       public virtual System.Object RemoveLast()
+                       {
+                               System.Object objectRemoved = this[this.Count-1];
+                               base.RemoveAt(this.Count-1);
+                               return objectRemoved;
+                       }
+
+                       /// <summary>
+                       /// Removes all the elements that aren't contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to verify the elements that will be retained.</param>
+                       /// <returns>Returns true if all the elements were successfully removed. Otherwise returns false.</returns>
+                       public virtual bool RetainAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               ListCollectionSupport tempCollection = new ListCollectionSupport(collection);
+                               while (tempEnumerator.MoveNext())
+                                       if (!tempCollection.Contains(tempEnumerator.Current))
+                                       {
+                                               result = this.RemoveElement(tempEnumerator.Current);
+                                       
+                                               if (result == true)
+                                               {
+                                                       tempEnumerator = this.GetEnumerator();
+                                               }
+                                       }
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Removes all the elements that aren't contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to verify the elements that will be retained.</param>
+                       /// <returns>Returns true if all the elements were successfully removed. Otherwise returns false.</returns>
+                       public virtual bool RetainAll(CollectionSupport collection)
+                       {
+                               return this.RetainAll((System.Collections.ICollection) collection);
+                       }               
+
+                       /// <summary>
+                       /// Verifies if all the elements of the specified collection are contained into the current collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be verified.</param>
+                       /// <returns>Returns true if all the elements are contained in the collection. Otherwise returns false.</returns>
+                       public virtual bool ContainsAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(collection).GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       if(!(result = this.Contains(tempEnumerator.Current)))
+                                               break;
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Verifies if all the elements of the specified collection are contained into the current collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be verified.</param>
+                       /// <returns>Returns true if all the elements are contained in the collection. Otherwise returns false.</returns>
+                       public virtual bool ContainsAll(CollectionSupport collection)
+                       {
+                               return this.ContainsAll((System.Collections.ICollection) collection);
+                       }               
+
+                       /// <summary>
+                       /// Returns a new list containing a portion of the current list between a specified range. 
+                       /// </summary>
+                       /// <param name="startIndex">The start index of the range.</param>
+                       /// <param name="endIndex">The end index of the range.</param>
+                       /// <returns>A ListCollectionSupport instance containing the specified elements.</returns>
+                       public virtual ListCollectionSupport SubList(int startIndex, int endIndex)
+                       {
+                               int index = 0;
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               ListCollectionSupport result = new ListCollectionSupport();
+                               for(index = startIndex; index < endIndex; index++)
+                                       result.Add(this[index]);
+                               return (ListCollectionSupport)result;
+                       }
+
+                       /// <summary>
+                       /// Obtains an array containing all the elements of the collection.
+                       /// </summary>
+                       /// <param name="objects">The array into which the elements of the collection will be stored.</param>
+                       /// <returns>The array containing all the elements of the collection.</returns>
+                       public virtual System.Object[] ToArray(System.Object[] objects)
+                       {       
+                               if (objects.Length < this.Count)
+                                       objects = new System.Object[this.Count];
+                               int index = 0;
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       objects[index++] = tempEnumerator.Current;
+                               return objects;
+                       }
+
+                       /// <summary>
+                       /// Returns an iterator of the collection starting at the specified position.
+                       /// </summary>
+                       /// <param name="index">The position to set the iterator.</param>
+                       /// <returns>An IEnumerator at the specified position.</returns>
+                       public virtual System.Collections.IEnumerator ListIterator(int index)
+                       {
+                               if ((index < 0) || (index > this.Count)) throw new System.IndexOutOfRangeException();                   
+                               System.Collections.IEnumerator tempEnumerator= this.GetEnumerator();
+                               if (index > 0)
+                               {
+                                       int i=0;
+                                       while ((tempEnumerator.MoveNext()) && (i < index - 1))
+                                               i++;
+                               }
+                               return tempEnumerator;                  
+                       }
+       
+                       /// <summary>
+                       /// Gets the last value from a list.
+                       /// </summary>
+                       /// <returns>Returns the last element of the list.</returns>
+                       public virtual System.Object GetLast()
+                       {
+                               if (this.Count == 0) throw new System.ArgumentOutOfRangeException();
+                               else
+                               {
+                                       return this[this.Count - 1];
+                               }                                                                        
+                       }
+               
+                       /// <summary>
+                       /// Return whether this list is empty.
+                       /// </summary>
+                       /// <returns>True if the list is empty, false if it isn't.</returns>
+                       public virtual bool IsEmpty()
+                       {
+                               return (this.Count == 0);
+                       }
+               
+                       /// <summary>
+                       /// Replaces the element at the specified position in this list with the specified element.
+                       /// </summary>
+                       /// <param name="index">Index of element to replace.</param>
+                       /// <param name="element">Element to be stored at the specified position.</param>
+                       /// <returns>The element previously at the specified position.</returns>
+                       public virtual System.Object Set(int index, System.Object element)
+                       {
+                               System.Object result = this[index];
+                               this[index] = element;
+                               return result;
+                       } 
+
+                       /// <summary>
+                       /// Returns the element at the specified position in the list.
+                       /// </summary>
+                       /// <param name="index">Index of element to return.</param>
+                       /// <param name="element">Element to be stored at the specified position.</param>
+                       /// <returns>The element at the specified position in the list.</returns>
+                       public virtual System.Object Get(int index)
+                       {
+                               return this[index];
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// This class manages array operations.
+               /// </summary>
+               public class ArraysSupport
+               {
+                       /// <summary>
+                       /// Compares the entire members of one array whith the other one.
+                       /// </summary>
+                       /// <param name="array1">The array to be compared.</param>
+                       /// <param name="array2">The array to be compared with.</param>
+                       /// <returns>True if both arrays are equals otherwise it returns false.</returns>
+                       /// <remarks>Two arrays are equal if they contains the same elements in the same order.</remarks>
+                       public static bool IsArrayEqual(System.Array array1, System.Array array2)
+                       {
+                               if (array1.Length != array2.Length)
+                                       return false;
+                               for (int i = 0; i < array1.Length; i++)
+                                       if (!(array1.GetValue(i).Equals(array2.GetValue(i))))
+                                               return false;
+                               return true;
+                       }
+
+                       /// <summary>
+                       /// Fills the array with an specific value from an specific index to an specific index.
+                       /// </summary>
+                       /// <param name="array">The array to be filled.</param>
+                       /// <param name="fromindex">The first index to be filled.</param>
+                       /// <param name="toindex">The last index to be filled.</param>
+                       /// <param name="val">The value to fill the array with.</param>
+                       public static void FillArray(System.Array array, System.Int32 fromindex,System.Int32 toindex, System.Object val)
+                       {
+                               System.Object Temp_Object = val;
+                               System.Type elementtype = array.GetType().GetElementType();
+                               if (elementtype != val.GetType())
+                                       Temp_Object = System.Convert.ChangeType(val, elementtype);
+                               if (array.Length == 0)
+                                       throw (new System.NullReferenceException());
+                               if (fromindex > toindex)
+                                       throw (new System.ArgumentException());
+                               if ((fromindex < 0) || ((System.Array)array).Length < toindex)
+                                       throw (new System.IndexOutOfRangeException());
+                               for (int index = (fromindex > 0) ? fromindex-- : fromindex; index < toindex; index++)
+                                       array.SetValue(Temp_Object, index);
+                       }
+
+                       /// <summary>
+                       /// Fills the array with an specific value.
+                       /// </summary>
+                       /// <param name="array">The array to be filled.</param>
+                       /// <param name="val">The value to fill the array with.</param>
+                       public static void FillArray(System.Array array, System.Object val)
+                       {
+                               FillArray(array, 0, array.Length, val);
+                       }
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// This class manages a set of elements.
+               /// </summary>
+               public class SetSupport : System.Collections.ArrayList
+               {
+                       /// <summary>
+                       /// Creates a new set.
+                       /// </summary>
+                       public SetSupport(): base()
+                       {           
+                       }
+
+                       /// <summary>
+                       /// Creates a new set initialized with System.Collections.ICollection object
+                       /// </summary>
+                       /// <param name="collection">System.Collections.ICollection object to initialize the set object</param>
+                       public SetSupport(System.Collections.ICollection collection): base(collection)
+                       {           
+                       }
+
+                       /// <summary>
+                       /// Creates a new set initialized with a specific capacity.
+                       /// </summary>
+                       /// <param name="capacity">value to set the capacity of the set object</param>
+                       public SetSupport(int capacity): base(capacity)
+                       {           
+                       }
+        
+                       /// <summary>
+                       /// Adds an element to the set.
+                       /// </summary>
+                       /// <param name="objectToAdd">The object to be added.</param>
+                       /// <returns>True if the object was added, false otherwise.</returns>
+                       public new virtual bool Add(object objectToAdd)
+                       {
+                               if (this.Contains(objectToAdd))
+                                       return false;
+                               else
+                               {
+                                       base.Add(objectToAdd);
+                                       return true;
+                               }
+                       }
+        
+                       /// <summary>
+                       /// Adds all the elements contained in the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               if (collection!=null)
+                               {
+                                       System.Collections.IEnumerator tempEnumerator = new System.Collections.ArrayList(collection).GetEnumerator();
+                                       while (tempEnumerator.MoveNext())
+                                       {
+                                               if (tempEnumerator.Current != null)
+                                                       result = this.Add(tempEnumerator.Current);
+                                       }
+                               }
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Adds all the elements contained in the specified support class collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be added.</param>
+                       /// <returns>Returns true if all the elements were successfuly added. Otherwise returns false.</returns>
+                       public virtual bool AddAll(CollectionSupport collection)
+                       {
+                               return this.AddAll((System.Collections.ICollection)collection);
+                       }
+        
+                       /// <summary>
+                       /// Verifies that all the elements of the specified collection are contained into the current collection. 
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be verified.</param>
+                       /// <returns>True if the collection contains all the given elements.</returns>
+                       public virtual bool ContainsAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = collection.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       if (!(result = this.Contains(tempEnumerator.Current)))
+                                               break;
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Verifies if all the elements of the specified collection are contained into the current collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be verified.</param>
+                       /// <returns>Returns true if all the elements are contained in the collection. Otherwise returns false.</returns>
+                       public virtual bool ContainsAll(CollectionSupport collection)
+                       {
+                               return this.ContainsAll((System.Collections.ICollection) collection);
+                       }               
+        
+                       /// <summary>
+                       /// Verifies if the collection is empty.
+                       /// </summary>
+                       /// <returns>True if the collection is empty, false otherwise.</returns>
+                       public virtual bool IsEmpty()
+                       {
+                               return (this.Count == 0);
+                       }
+                
+                       /// <summary>
+                       /// Removes an element from the set.
+                       /// </summary>
+                       /// <param name="elementToRemove">The element to be removed.</param>
+                       /// <returns>True if the element was removed.</returns>
+                       public new virtual bool Remove(object elementToRemove)
+                       {
+                               bool result = false;
+                               if (this.Contains(elementToRemove))
+                                       result = true;
+                               base.Remove(elementToRemove);
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Removes all the elements contained in the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be removed.</param>
+                       /// <returns>True if all the elements were successfuly removed, false otherwise.</returns>
+                       public virtual bool RemoveAll(System.Collections.ICollection collection)
+                       { 
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = collection.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                               {
+                                       if ((result == false) && (this.Contains(tempEnumerator.Current)))
+                                               result = true;
+                                       this.Remove(tempEnumerator.Current);
+                               }
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Removes all the elements contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to extract the elements that will be removed.</param>
+                       /// <returns>Returns true if all the elements were successfuly removed. Otherwise returns false.</returns>
+                       public virtual bool RemoveAll(CollectionSupport collection)
+                       { 
+                               return this.RemoveAll((System.Collections.ICollection) collection);
+                       }               
+
+                       /// <summary>
+                       /// Removes all the elements that aren't contained in the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to verify the elements that will be retained.</param>
+                       /// <returns>True if all the elements were successfully removed, false otherwise.</returns>
+                       public virtual bool RetainAll(System.Collections.ICollection collection)
+                       {
+                               bool result = false;
+                               System.Collections.IEnumerator tempEnumerator = collection.GetEnumerator();
+                               SetSupport tempSet = (SetSupport)collection;
+                               while (tempEnumerator.MoveNext())
+                                       if (!tempSet.Contains(tempEnumerator.Current))
+                                       {
+                                               result = this.Remove(tempEnumerator.Current);
+                                               tempEnumerator = this.GetEnumerator();
+                                       }
+                               return result;
+                       }
+               
+                       /// <summary>
+                       /// Removes all the elements that aren't contained into the specified collection.
+                       /// </summary>
+                       /// <param name="collection">The collection used to verify the elements that will be retained.</param>
+                       /// <returns>Returns true if all the elements were successfully removed. Otherwise returns false.</returns>
+                       public virtual bool RetainAll(CollectionSupport collection)
+                       {
+                               return this.RetainAll((System.Collections.ICollection) collection);
+                       }               
+        
+                       /// <summary>
+                       /// Obtains an array containing all the elements of the collection.
+                       /// </summary>
+                       /// <returns>The array containing all the elements of the collection.</returns>
+                       public new virtual object[] ToArray()
+                       {
+                               int index = 0;
+                               object[] tempObject= new object[this.Count];
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       tempObject[index++] = tempEnumerator.Current;
+                               return tempObject;
+                       }
+
+                       /// <summary>
+                       /// Obtains an array containing all the elements in the collection.
+                       /// </summary>
+                       /// <param name="objects">The array into which the elements of the collection will be stored.</param>
+                       /// <returns>The array containing all the elements of the collection.</returns>
+                       public virtual object[] ToArray(object[] objects)
+                       {
+                               int index = 0;
+                               System.Collections.IEnumerator tempEnumerator = this.GetEnumerator();
+                               while (tempEnumerator.MoveNext())
+                                       objects[index++] = tempEnumerator.Current;
+                               return objects;
+                       }
+               }
+               /*******************************/
+               /// <summary>
+               /// This class manages different operation with collections.
+               /// </summary>
+               public class AbstractSetSupport : SetSupport
+               {
+                       /// <summary>
+                       /// The constructor with no parameters to create an abstract set.
+                       /// </summary>
+                       public AbstractSetSupport()
+                       {
+                       }
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// Removes the element with the specified key from a Hashtable instance.
+               /// </summary>
+               /// <param name="hashtable">The Hashtable instance</param>
+               /// <param name="key">The key of the element to remove</param>
+               /// <returns>The element removed</returns>  
+               public static System.Object HashtableRemove(System.Collections.Hashtable hashtable, System.Object key)
+               {
+                       System.Object element = hashtable[key];
+                       hashtable.Remove(key);
+                       return element;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Sets the size of the ArrayList. If the new size is greater than the current capacity, then new null items are added to the end of the ArrayList. If the new size is lower than the current size, then all elements after the new size are discarded
+               /// </summary>
+               /// <param name="arrayList">The ArrayList to be changed</param>
+               /// <param name="newSize">The new ArrayList size</param>
+               public static void SetSize(System.Collections.ArrayList arrayList, int newSize)
+               {
+                       if (newSize < 0) throw new System.ArgumentException();
+                       else
+                       {
+                               if (newSize < arrayList.Count)
+                                       arrayList.RemoveRange(newSize,(arrayList.Count-newSize));
+                               else
+                                       while(newSize > arrayList.Count)
+                                               arrayList.Add(null);
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Adds an element to the top end of a Stack instance.
+               /// </summary>
+               /// <param name="stack">The Stack instance</param>
+               /// <param name="element">The element to add</param>
+               /// <returns>The element added</returns>  
+               public static System.Object StackPush(System.Collections.Stack stack, System.Object element)
+               {
+                       stack.Push(element);
+                       return element;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Copies an array of chars obtained from a String into a specified array of chars
+               /// </summary>
+               /// <param name="sourceString">The String to get the chars from</param>
+               /// <param name="sourceStart">Position of the String to start getting the chars</param>
+               /// <param name="sourceEnd">Position of the String to end getting the chars</param>
+               /// <param name="destinationArray">Array to return the chars</param>
+               /// <param name="destinationStart">Position of the destination array of chars to start storing the chars</param>
+               /// <returns>An array of chars</returns>
+               public static void GetCharsFromString(string sourceString, int sourceStart, int sourceEnd, ref char[] destinationArray, int destinationStart)
+               {       
+                       int sourceCounter;
+                       int destinationCounter;
+                       sourceCounter = sourceStart;
+                       destinationCounter = destinationStart;
+                       while (sourceCounter < sourceEnd)
+                       {
+                               destinationArray[destinationCounter] = (char) sourceString[sourceCounter];
+                               sourceCounter++;
+                               destinationCounter++;
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Creates an output file stream to write to the file with the specified name.
+               /// </summary>
+               /// <param name="FileName">Name of the file to write.</param>
+               /// <param name="Append">True in order to write to the end of the file, false otherwise.</param>
+               /// <returns>New instance of FileStream with the proper file mode.</returns>
+               public static System.IO.FileStream GetFileStream(string FileName, bool Append)
+               {
+                       if (Append)
+                               return new System.IO.FileStream(FileName, System.IO.FileMode.Append);
+                       else
+                               return new System.IO.FileStream(FileName, System.IO.FileMode.Create);
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// Converts an array of sbytes to an array of chars
+               /// </summary>
+               /// <param name="sByteArray">The array of sbytes to convert</param>
+               /// <returns>The new array of chars</returns>
+               [CLSCompliantAttribute(false)]
+               public static char[] ToCharArray(sbyte[] sByteArray) 
+               {
+                       char[] charArray = new char[sByteArray.Length];    
+                       sByteArray.CopyTo(charArray, 0);
+                       return charArray;
+               }
+
+               /// <summary>
+               /// Converts an array of bytes to an array of chars
+               /// </summary>
+               /// <param name="byteArray">The array of bytes to convert</param>
+               /// <returns>The new array of chars</returns>
+               public static char[] ToCharArray(byte[] byteArray) 
+               {
+                       char[] charArray = new char[byteArray.Length];     
+                       byteArray.CopyTo(charArray, 0);
+                       return charArray;
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Encapsulates the functionality of message digest algorithms such as SHA-1 or MD5.
+               /// </summary>
+               public class MessageDigestSupport
+               {
+                       private System.Security.Cryptography.HashAlgorithm algorithm;
+                       private byte[] data;
+                       private int position;
+                       private string algorithmName;
+
+                       /// <summary>
+                       /// The HashAlgorithm instance that provide the cryptographic hash algorithm
+                       /// </summary>
+                       public System.Security.Cryptography.HashAlgorithm Algorithm
+                       {
+                               get
+                               {
+                                       return this.algorithm;
+                               }
+                               set
+                               {
+                                       this.algorithm  = value;
+                               }
+                       }
+
+                       /// <summary>
+                       /// The digest data
+                       /// </summary>
+                       public byte[] Data
+                       {
+                               get
+                               {
+                                       return this.data;
+                               }
+                               set
+                               {
+                                       this.data  = value;
+                               }
+                       }
+
+                       /// <summary>
+                       /// The name of the cryptographic hash algorithm used in the instance
+                       /// </summary>
+                       public string AlgorithmName
+                       {
+                               get
+                               {
+                                       return this.algorithmName;
+                               }
+                       }
+
+                       /// <summary>
+                       /// Creates a message digest using the specified name to set Algorithm property.
+                       /// </summary>
+                       /// <param name="algorithm">The name of the algorithm to use</param>
+                       public MessageDigestSupport(System.String algorithm)
+                       {                       
+                               if (algorithm.Equals("SHA-1"))
+                               {
+                                       this.algorithmName = "SHA";
+                               }
+                               else 
+                               {
+                                       this.algorithmName = algorithm;
+                               }
+                               this.Algorithm = (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.CryptoConfig.CreateFromName(this.algorithmName);                     
+                               this.position  = 0;
+                       }
+
+                       /// <summary>
+                       /// Computes the hash value for the internal data digest.
+                       /// </summary>
+                       /// <returns>The array of signed bytes with the resulting hash value</returns>
+                       [CLSCompliantAttribute(false)]
+                       public sbyte[] DigestData()
+                       {
+                               sbyte[] result = ToSByteArray(this.Algorithm.ComputeHash(this.data));
+                               this.Reset();
+                               return result;
+                       }
+
+                       /// <summary>
+                       /// Performs and update on the digest with the specified array and then completes the digest
+                       /// computation.
+                       /// </summary>
+                       /// <param name="newData">The array of bytes for final update to the digest</param>
+                       /// <returns>An array of signed bytes with the resulting hash value</returns>
+                       [CLSCompliantAttribute(false)]
+                       public sbyte[] DigestData(byte[] newData)
+                       {
+                               this.Update(newData);
+                               return this.DigestData();
+                       }
+
+                       /// <summary>
+                       /// Updates the digest data with the specified array of bytes by making an append
+                       /// operation in the internal array of data.
+                       /// </summary>
+                       /// <param name="newData">The array of bytes for the update operation</param>
+                       public void Update(byte[] newData)
+                       {
+                               if (position == 0)
+                               {
+                                       this.Data = newData;
+                                       this.position = this.Data.Length - 1;
+                               }
+                               else
+                               {
+                                       byte[] oldData = this.Data;
+                                       this.Data = new byte[newData.Length + position + 1];
+                                       oldData.CopyTo(this.Data, 0);
+                                       newData.CopyTo(this.Data, oldData.Length);
+                   
+                                       this.position = this.Data.Length - 1;
+                               }
+                       }
+        
+                       /// <summary>
+                       /// Updates the digest data with the input byte by calling the method Update with an array.
+                       /// </summary>
+                       /// <param name="newData">The input byte for the update</param>
+                       public void Update(byte newData)
+                       {
+                               byte[] newDataArray = new byte[1];
+                               newDataArray[0] = newData;
+                               this.Update(newDataArray);
+                       }
+
+                       /// <summary>
+                       /// Updates the specified count of bytes with the input array of bytes starting at the
+                       /// input offset.
+                       /// </summary>
+                       /// <param name="newData">The array of bytes for the update operation</param>
+                       /// <param name="offset">The initial position to start from in the array of bytes</param>
+                       /// <param name="count">The number of bytes fot the update</param>
+                       public void Update(byte[] newData, int offset, int count)
+                       {
+                               byte[] newDataArray = new byte[count];
+                               System.Array.Copy(newData, offset, newDataArray, 0, count);
+                               this.Update(newDataArray);
+                       }
+               
+                       /// <summary>
+                       /// Resets the digest data to the initial state.
+                       /// </summary>
+                       public void Reset()
+                       {
+                               this.data = null;
+                               this.position = 0;
+                       }
+
+                       /// <summary>
+                       /// Returns a string representation of the Message Digest
+                       /// </summary>
+                       /// <returns>A string representation of the object</returns>
+                       public override string ToString()
+                       {
+                               return this.Algorithm.ToString();
+                       }
+
+                       /// <summary>
+                       /// Generates a new instance of the MessageDigestSupport class using the specified algorithm
+                       /// </summary>
+                       /// <param name="algorithm">The name of the algorithm to use</param>
+                       /// <returns>A new instance of the MessageDigestSupport class</returns>
+                       public static MessageDigestSupport GetInstance(System.String algorithm)
+                       {
+                               return new MessageDigestSupport(algorithm);
+                       }
+               
+                       /// <summary>
+                       /// Compares two arrays of signed bytes evaluating equivalence in digest data
+                       /// </summary>
+                       /// <param name="firstDigest">An array of signed bytes for comparison</param>
+                       /// <param name="secondDigest">An array of signed bytes for comparison</param>
+                       /// <returns>True if the input digest arrays are equal</returns>
+                       [CLSCompliantAttribute(false)]
+                       public static bool EquivalentDigest(System.SByte[] firstDigest, System.SByte[] secondDigest)
+                       {
+                               bool result = false;
+                               if (firstDigest.Length == secondDigest.Length)
+                               {
+                                       int index = 0;
+                                       result = true;
+                                       while(result && index < firstDigest.Length)
+                                       {
+                                               result = firstDigest[index] == secondDigest[index];
+                                               index++;
+                                       }
+                               }
+                       
+                               return result;
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// This class uses a cryptographic Random Number Generator to provide support for
+               /// strong pseudo-random number generation.
+               /// </summary>
+               public class SecureRandomSupport
+               {
+                       private System.Security.Cryptography.RNGCryptoServiceProvider generator;
+
+                       /// <summary>
+                       /// Initializes a new instance of the random number generator.
+                       /// </summary>
+                       public SecureRandomSupport()
+                       {
+                               this.generator = new System.Security.Cryptography.RNGCryptoServiceProvider();
+                       }
+
+                       /// <summary>
+                       /// Initializes a new instance of the random number generator with the given seed.
+                       /// </summary>
+                       /// <param name="seed">The initial seed for the generator</param>
+                       public SecureRandomSupport(byte[] seed)
+                       {
+                               this.generator = new System.Security.Cryptography.RNGCryptoServiceProvider(seed);
+                       }
+
+                       /// <summary>
+                       /// Returns an array of bytes with a sequence of cryptographically strong random values
+                       /// </summary>
+                       /// <param name="randomnumbersarray">The array of bytes to fill</param>
+                       [CLSCompliantAttribute(false)]
+                       public sbyte[] NextBytes(byte[] randomnumbersarray)
+                       {                       
+                               this.generator.GetBytes(randomnumbersarray);
+                               return ToSByteArray(randomnumbersarray);
+                       }
+
+                       /// <summary>
+                       /// Returns the given number of seed bytes generated for the first running of a new instance 
+                       /// of the random number generator
+                       /// </summary>
+                       /// <param name="numberOfBytes">Number of seed bytes to generate</param>
+                       /// <returns>Seed bytes generated</returns>
+                       public static byte[] GetSeed(int numberOfBytes)
+                       {
+                               System.Security.Cryptography.RNGCryptoServiceProvider generatedSeed = new System.Security.Cryptography.RNGCryptoServiceProvider();
+                               byte[] seeds = new byte[numberOfBytes];
+                               generatedSeed.GetBytes(seeds);
+                               return seeds;
+                       }
+
+                       /// <summary>
+                       /// Creates a new instance of the random number generator with the seed provided by the user
+                       /// </summary>
+                       /// <param name="newSeed">Seed to create a new random number generator</param>
+                       public void SetSeed(byte[] newSeed)
+                       {
+                               this.generator = new System.Security.Cryptography.RNGCryptoServiceProvider(newSeed);
+                       }
+
+                       /// <summary>
+                       /// Creates a new instance of the random number generator with the seed provided by the user
+                       /// </summary>
+                       /// <param name="newSeed">Seed to create a new random number generator</param>
+                       public void SetSeed(long newSeed)
+                       {
+                               byte[] bytes = new byte[8];
+                               for (int index= 7; index > 0 ; index--)
+                               {
+                                       bytes[index] = (byte)(newSeed - (long)((newSeed >> 8) << 8));
+                                       newSeed  = (long)(newSeed >> 8);
+                               }                       
+                               SetSeed(bytes);
+                       }
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Interface used by classes which must be single threaded.
+               /// </summary>
+               public interface SingleThreadModel
+               {
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// Creates an instance of a received Type.
+               /// </summary>
+               /// <param name="classType">The Type of the new class instance to return.</param>
+               /// <returns>An Object containing the new instance.</returns>
+               public static System.Object CreateNewInstance(System.Type classType)
+               {
+                       System.Object instance = null;
+                       System.Type[] constructor = new System.Type[]{};
+                       System.Reflection.ConstructorInfo[] constructors = null;
+       
+                       constructors = classType.GetConstructors();
+
+                       if (constructors.Length == 0)
+                               throw new System.UnauthorizedAccessException();
+                       else
+                       {
+                               for(int i = 0; i < constructors.Length; i++)
+                               {
+                                       System.Reflection.ParameterInfo[] parameters = constructors[i].GetParameters();
+
+                                       if (parameters.Length == 0)
+                                       {
+                                               instance = classType.GetConstructor(constructor).Invoke(new System.Object[]{});
+                                               break;
+                                       }
+                                       else if (i == constructors.Length -1)     
+                                               throw new System.MethodAccessException();
+                               }                       
+                       }
+                       return instance;
+               }
+
+
+               /*******************************/
+               /// <summary>
+               /// Writes the exception stack trace to the received stream
+               /// </summary>
+               /// <param name="throwable">Exception to obtain information from</param>
+               /// <param name="stream">Output sream used to write to</param>
+               public static void WriteStackTrace(System.Exception throwable, System.IO.TextWriter stream)
+               {
+                       stream.Write(throwable.StackTrace);
+                       stream.Flush();
+               }
+
+               /*******************************/
+               /// <summary>
+               /// Determines whether two Collections instances are equals.
+               /// </summary>
+               /// <param name="source">The first Collections to compare. </param>
+               /// <param name="target">The second Collections to compare. </param>
+               /// <returns>Return true if the first collection is the same instance as the second collection, otherwise return false.</returns>
+               public static bool EqualsSupport(System.Collections.ICollection source, System.Collections.ICollection target )
+               {
+                       System.Collections.IEnumerator sourceEnumerator = ReverseStack(source);
+                       System.Collections.IEnumerator targetEnumerator = ReverseStack(target);
+     
+                       if (source.Count != target.Count)
+                               return false;
+                       while(sourceEnumerator.MoveNext() && targetEnumerator.MoveNext())
+                               if (!sourceEnumerator.Current.Equals(targetEnumerator.Current))
+                                       return false;
+                       return true;
+               }
+       
+               /// <summary>
+               /// Determines if a Collection is equal to the Object.
+               /// </summary>
+               /// <param name="source">The first Collections to compare.</param>
+               /// <param name="target">The Object to compare.</param>
+               /// <returns>Return true if the first collection contains the same values of the second Object, otherwise return false.</returns>
+               public static bool EqualsSupport(System.Collections.ICollection source, System.Object target)
+               {
+                       if((target.GetType())!= (typeof(System.Collections.ICollection)))
+                               return false;
+                       else
+                               return EqualsSupport(source,(System.Collections.ICollection)target);
+               }
+
+               /// <summary>
+               /// Determines if a IDictionaryEnumerator is equal to the Object.
+               /// </summary>
+               /// <param name="source">The first IDictionaryEnumerator to compare.</param>
+               /// <param name="target">The second Object to compare.</param>
+               /// <returns>Return true if the first IDictionaryEnumerator contains the same values of the second Object, otherwise return false.</returns>
+               public static bool EqualsSupport(System.Collections.IDictionaryEnumerator source, System.Object target)
+               {
+                       if((target.GetType())!= (typeof(System.Collections.IDictionaryEnumerator)))
+                               return false;
+                       else
+                               return EqualsSupport(source,(System.Collections.IDictionaryEnumerator)target);
+               }
+
+               /// <summary>
+               /// Determines whether two IDictionaryEnumerator instances are equals.
+               /// </summary>
+               /// <param name="source">The first IDictionaryEnumerator to compare.</param>
+               /// <param name="target">The second IDictionaryEnumerator to compare.</param>
+               /// <returns>Return true if the first IDictionaryEnumerator contains the same values as the second IDictionaryEnumerator, otherwise return false.</returns>
+               public static bool EqualsSupport(System.Collections.IDictionaryEnumerator source, System.Collections.IDictionaryEnumerator target )
+               {
+                       while(source.MoveNext() && target.MoveNext())
+                               if (source.Key.Equals(target.Key))
+                                       if(source.Value.Equals(target.Value))
+                                               return true;
+                       return false;
+               }
+
+               /// <summary>
+               /// Reverses the Stack Collection received.
+               /// </summary>
+               /// <param name="collection">The collection to reverse.</param>
+               /// <returns>The collection received in reverse order if it was a System.Collections.Stack type, otherwise it does 
+               /// nothing to the collection.</returns>
+               public static System.Collections.IEnumerator ReverseStack(System.Collections.ICollection collection)
+               {
+                       if((collection.GetType()) == (typeof(System.Collections.Stack)))
+                       {
+                               System.Collections.ArrayList collectionStack = new System.Collections.ArrayList(collection);
+                               collectionStack.Reverse();
+                               return collectionStack.GetEnumerator();
+                       }
+                       else
+                               return collection.GetEnumerator();
+               }
+
+       }