/******************************************************************************
* 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:
///
/// - BIND_REQUEST = 0;
/// - BIND_RESPONSE = 1;
/// - UNBIND_REQUEST = 2;
/// - SEARCH_REQUEST = 3;
/// - SEARCH_RESPONSE = 4;
/// - SEARCH_RESULT = 5;
/// - MODIFY_REQUEST = 6;
/// - MODIFY_RESPONSE = 7;
/// - ADD_REQUEST = 8;
/// - ADD_RESPONSE = 9;
/// - DEL_REQUEST = 10;
/// - DEL_RESPONSE = 11;
/// - MODIFY_RDN_REQUEST = 12;
/// - MODIFY_RDN_RESPONSE = 13;
/// - COMPARE_REQUEST = 14;
/// - COMPARE_RESPONSE = 15;
/// - ABANDON_REQUEST = 16;
/// - SEARCH_RESULT_REFERENCE = 19;
/// - EXTENDED_REQUEST = 23;
/// - EXTENDED_RESPONSE = 24;
/// - INTERMEDIATE_RESPONSE = 25;
///
///
///
/// 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();
}
}
}