/****************************************************************************** * 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 { /// The base class for Ldap request and response messages. /// /// Subclassed by response messages used in asynchronous operations. /// /// /// public class LdapMessage { /// Returns the LdapMessage request associated with this response virtual internal LdapMessage RequestingMessage { /* package */ get { return message.RequestingMessage; } } /// Returns any controls in the message. 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; } } /// Returns the message ID. The message ID is an integer value /// identifying the Ldap request and its response. /// virtual public int MessageID { get { if (imsgNum == - 1) { imsgNum = message.MessageID; } return imsgNum; } } /// Returns the Ldap operation type of the message. /// /// The type is one of the following: /// /// /// /// The operation type of the message. /// virtual public int Type { get { if (messageType == - 1) { messageType = message.Type; } return messageType; } } /// Indicates whether the message is a request or a response /// /// /// true if the message is a request, false if it is a response, /// a search result, or a search result reference. /// virtual public bool Request { get { return message.isRequest(); } } /// Returns the RFC 2251 LdapMessage composed in this object. 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; case INTERMEDIATE_RESPONSE: name = "LdapIntermediateResponse"; break; default: throw new System.SystemException("LdapMessage: Unknown Type " + Type); } return name; } } /// Retrieves the identifier tag for this message. /// /// An identifier can be associated with a message with the /// setTag method. /// Tags are set by the application and not by the API or the server. /// If a server response isRequest() == false has no tag, /// the tag associated with the corresponding server request is used. /// /// /// the identifier associated with this message or null /// if none. /// /// /// Sets a string identifier tag for this message. /// /// 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. /// /// 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. /// /// 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. /// /// /// the String assigned to identify this message. /// /// 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 ; } } /// A bind request operation. /// /// BIND_REQUEST = 0 /// public const int BIND_REQUEST = 0; /// A bind response operation. /// /// BIND_RESPONSE = 1 /// public const int BIND_RESPONSE = 1; /// An unbind request operation. /// /// UNBIND_REQUEST = 2 /// public const int UNBIND_REQUEST = 2; /// A search request operation. /// /// SEARCH_REQUEST = 3 /// public const int SEARCH_REQUEST = 3; /// A search response containing data. /// /// SEARCH_RESPONSE = 4 /// public const int SEARCH_RESPONSE = 4; /// A search result message - contains search status. /// /// SEARCH_RESULT = 5 /// public const int SEARCH_RESULT = 5; /// A modify request operation. /// /// MODIFY_REQUEST = 6 /// public const int MODIFY_REQUEST = 6; /// A modify response operation. /// /// MODIFY_RESPONSE = 7 /// public const int MODIFY_RESPONSE = 7; /// An add request operation. /// /// ADD_REQUEST = 8 /// public const int ADD_REQUEST = 8; /// An add response operation. /// /// ADD_RESONSE = 9 /// public const int ADD_RESPONSE = 9; /// A delete request operation. /// /// DEL_REQUEST = 10 /// public const int DEL_REQUEST = 10; /// A delete response operation. /// /// DEL_RESONSE = 11 /// public const int DEL_RESPONSE = 11; /// A modify RDN request operation. /// /// MODIFY_RDN_REQUEST = 12 /// public const int MODIFY_RDN_REQUEST = 12; /// A modify RDN response operation. /// /// MODIFY_RDN_RESPONSE = 13 /// public const int MODIFY_RDN_RESPONSE = 13; /// A compare result operation. /// /// COMPARE_REQUEST = 14 /// public const int COMPARE_REQUEST = 14; /// A compare response operation. /// /// COMPARE_RESPONSE = 15 /// public const int COMPARE_RESPONSE = 15; /// An abandon request operation. /// /// ABANDON_REQUEST = 16 /// public const int ABANDON_REQUEST = 16; /// A search result reference operation. /// /// SEARCH_RESULT_REFERENCE = 19 /// public const int SEARCH_RESULT_REFERENCE = 19; /// An extended request operation. /// /// EXTENDED_REQUEST = 23 /// public const int EXTENDED_REQUEST = 23; /// An extended response operation. /// /// EXTENDED_RESONSE = 24 /// public const int EXTENDED_RESPONSE = 24; /// An intermediate response operation. /// /// INTERMEDIATE_RESONSE = 25 /// public const int INTERMEDIATE_RESPONSE = 25; /// A request or response message for an asynchronous Ldap operation. protected internal RfcLdapMessage message; /// Lock object to protect counter for message numbers /* private static Object msgLock = new Object(); */ /// Counters used to construct request message #'s, unique for each request /// Will be enabled after ASN.1 conversion /// /* 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; /// Dummy constuctor /* package */ internal LdapMessage() { return ; } /// Creates an LdapMessage when sending a protocol operation and sends /// some optional controls with the message. /// /// /// The operation type of message. /// /// /// The controls to use with the operation. /// /// /// /// /*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 ; } /// Creates an Rfc 2251 LdapMessage when the libraries receive a response /// from a command. /// /// /// A response message. /// protected internal LdapMessage(RfcLdapMessage message) { this.message = message; return ; } /// Returns a mutated clone of this LdapMessage, /// replacing base dn, filter. /// /// /// the base dn /// /// /// the filter /// /// /// true if a search reference /// /// /// the object representing the new message /// /* package */ internal LdapMessage Clone(System.String dn, System.String filter, bool reference) { return new LdapMessage((RfcLdapMessage) message.dupMessage(dn, filter, reference)); } /// 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 /// /// 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); } /// Creates a String representation of this object /// /// /// a String representation for this LdapMessage /// public override System.String ToString() { return Name + "(" + MessageID + "): " + message.ToString(); } } }