1 /******************************************************************************
3 * Copyright (c) 2003 Novell Inc. www.novell.com
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 *******************************************************************************/
24 // Novell.Directory.Ldap.LdapMessage.cs
27 // Sunil Kumar (Sunilk@novell.com)
29 // (C) 2003 Novell, Inc (http://www.novell.com)
33 using Novell
.Directory
.Ldap
.Rfc2251
;
34 using Novell
.Directory
.Ldap
.Asn1
;
35 using Novell
.Directory
.Ldap
.Utilclass
;
37 namespace Novell
.Directory
.Ldap
40 /// <summary> The base class for Ldap request and response messages.
42 /// Subclassed by response messages used in asynchronous operations.
46 public class LdapMessage
48 /// <summary> Returns the LdapMessage request associated with this response</summary>
49 virtual internal LdapMessage RequestingMessage
55 return message
.RequestingMessage
;
59 /// <summary> Returns any controls in the message.</summary>
60 virtual public LdapControl
[] Controls
65 /* LdapControl[] controls = null;
66 RfcControls asn1Ctrls = message.Controls;
68 if (asn1Ctrls != null)
70 controls = new LdapControl[asn1Ctrls.size()];
71 for (int i = 0; i < asn1Ctrls.size(); i++)
73 RfcControl rfcCtl = (RfcControl) asn1Ctrls.get_Renamed(i);
74 System.String oid = rfcCtl.ControlType.stringValue();
75 sbyte[] value_Renamed = rfcCtl.ControlValue.byteValue();
76 bool critical = rfcCtl.Criticality.booleanValue();
78 controls[i] = controlFactory(oid, critical, value_Renamed);
84 LdapControl
[] controls
= null;
85 RfcControls asn1Ctrls
= message
.Controls
;
87 // convert from RFC 2251 Controls to LDAPControl[].
88 if (asn1Ctrls
!= null)
90 controls
= new LdapControl
[asn1Ctrls
.size()];
91 for (int i
= 0; i
< asn1Ctrls
.size(); i
++)
95 * At this point we have an RfcControl which needs to be
96 * converted to the appropriate Response Control. This requires
97 * calling the constructor of a class that extends LDAPControl.
98 * The controlFactory method searches the list of registered
99 * controls and if a match is found calls the constructor
100 * for that child LDAPControl. Otherwise, it returns a regular
101 * LDAPControl object.
103 * Question: Why did we not call the controlFactory method when
104 * we were parsing the control. Answer: By the time the
105 * code realizes that we have a control it is already too late.
107 RfcControl rfcCtl
= (RfcControl
) asn1Ctrls
.get_Renamed(i
);
108 System
.String oid
= rfcCtl
.ControlType
.stringValue();
109 sbyte[] value_Renamed
= rfcCtl
.ControlValue
.byteValue();
110 bool critical
= rfcCtl
.Criticality
.booleanValue();
112 /* Return from this call should return either an LDAPControl
113 * or a class extending LDAPControl that implements the
114 * appropriate registered response control
116 controls
[i
] = controlFactory(oid
, critical
, value_Renamed
);
125 /// <summary> Returns the message ID. The message ID is an integer value
126 /// identifying the Ldap request and its response.
128 virtual public int MessageID
134 imsgNum
= message
.MessageID
;
140 /// <summary> Returns the Ldap operation type of the message.
142 /// The type is one of the following:
144 /// <li>BIND_REQUEST = 0;</li>
145 /// <li>BIND_RESPONSE = 1;</li>
146 /// <li>UNBIND_REQUEST = 2;</li>
147 /// <li>SEARCH_REQUEST = 3;</li>
148 /// <li>SEARCH_RESPONSE = 4;</li>
149 /// <li>SEARCH_RESULT = 5;</li>
150 /// <li>MODIFY_REQUEST = 6;</li>
151 /// <li>MODIFY_RESPONSE = 7;</li>
152 /// <li>ADD_REQUEST = 8;</li>
153 /// <li>ADD_RESPONSE = 9;</li>
154 /// <li>DEL_REQUEST = 10;</li>
155 /// <li>DEL_RESPONSE = 11;</li>
156 /// <li>MODIFY_RDN_REQUEST = 12;</li>
157 /// <li>MODIFY_RDN_RESPONSE = 13;</li>
158 /// <li>COMPARE_REQUEST = 14;</li>
159 /// <li>COMPARE_RESPONSE = 15;</li>
160 /// <li>ABANDON_REQUEST = 16;</li>
161 /// <li>SEARCH_RESULT_REFERENCE = 19;</li>
162 /// <li>EXTENDED_REQUEST = 23;</li>
163 /// <li>EXTENDED_RESPONSE = 24;</li>
167 /// <returns> The operation type of the message.
169 virtual public int Type
173 if (messageType
== - 1)
175 messageType
= message
.Type
;
181 /// <summary> Indicates whether the message is a request or a response
184 /// <returns> true if the message is a request, false if it is a response,
185 /// a search result, or a search result reference.
187 virtual public bool Request
191 return message
.isRequest();
195 /// <summary> Returns the RFC 2251 LdapMessage composed in this object.</summary>
196 virtual internal RfcLdapMessage Asn1Object
206 private System
.String Name
214 case SEARCH_RESPONSE
:
215 name
= "LdapSearchResponse";
219 name
= "LdapSearchResult";
223 name
= "LdapSearchRequest";
227 name
= "LdapModifyRequest";
230 case MODIFY_RESPONSE
:
231 name
= "LdapModifyResponse";
235 name
= "LdapAddRequest";
239 name
= "LdapAddResponse";
243 name
= "LdapDelRequest";
247 name
= "LdapDelResponse";
250 case MODIFY_RDN_REQUEST
:
251 name
= "LdapModifyRDNRequest";
254 case MODIFY_RDN_RESPONSE
:
255 name
= "LdapModifyRDNResponse";
258 case COMPARE_REQUEST
:
259 name
= "LdapCompareRequest";
262 case COMPARE_RESPONSE
:
263 name
= "LdapCompareResponse";
267 name
= "LdapBindRequest";
271 name
= "LdapBindResponse";
275 name
= "LdapUnbindRequest";
278 case ABANDON_REQUEST
:
279 name
= "LdapAbandonRequest";
282 case SEARCH_RESULT_REFERENCE
:
283 name
= "LdapSearchResultReference";
286 case EXTENDED_REQUEST
:
287 name
= "LdapExtendedRequest";
290 case EXTENDED_RESPONSE
:
291 name
= "LdapExtendedResponse";
295 throw new System
.SystemException("LdapMessage: Unknown Type " + Type
);
302 /// <summary> Retrieves the identifier tag for this message.
304 /// An identifier can be associated with a message with the
305 /// <code>setTag</code> method.
306 /// Tags are set by the application and not by the API or the server.
307 /// If a server response <code>isRequest() == false</code> has no tag,
308 /// the tag associated with the corresponding server request is used.
311 /// <returns> the identifier associated with this message or <code>null</code>
315 /// <summary> Sets a string identifier tag for this message.
317 /// This method allows an API to set a tag and later identify messages
318 /// by retrieving the tag associated with the message.
319 /// Tags are set by the application and not by the API or the server.
320 /// Message tags are not included with any message sent to or received
323 /// Tags set on a request to the server
324 /// are automatically associated with the response messages when they are
325 /// received by the API and transferred to the application.
326 /// The application can explicitly set a different value in a
327 /// response message.
329 /// To set a value in a server request, for example an
330 /// {@link LdapSearchRequest}, you must create the object,
331 /// set the tag, and use the
332 /// {@link LdapConnection.SendRequest LdapConnection.sendRequest()}
333 /// method to send it to the server.
336 /// <param name="stringTag"> the String assigned to identify this message.
339 virtual public System
.String Tag
343 if ((System
.Object
) this.stringTag
!= null)
345 return this.stringTag
;
351 LdapMessage m
= this.RequestingMessage
;
361 this.stringTag
= value;
367 /// <summary> A bind request operation.
371 public const int BIND_REQUEST
= 0;
373 /// <summary> A bind response operation.
375 /// BIND_RESPONSE = 1
377 public const int BIND_RESPONSE
= 1;
379 /// <summary> An unbind request operation.
381 /// UNBIND_REQUEST = 2
383 public const int UNBIND_REQUEST
= 2;
385 /// <summary> A search request operation.
387 /// SEARCH_REQUEST = 3
389 public const int SEARCH_REQUEST
= 3;
391 /// <summary> A search response containing data.
393 /// SEARCH_RESPONSE = 4
395 public const int SEARCH_RESPONSE
= 4;
397 /// <summary> A search result message - contains search status.
399 /// SEARCH_RESULT = 5
401 public const int SEARCH_RESULT
= 5;
403 /// <summary> A modify request operation.
405 /// MODIFY_REQUEST = 6
407 public const int MODIFY_REQUEST
= 6;
409 /// <summary> A modify response operation.
411 /// MODIFY_RESPONSE = 7
413 public const int MODIFY_RESPONSE
= 7;
415 /// <summary> An add request operation.
419 public const int ADD_REQUEST
= 8;
421 /// <summary> An add response operation.
425 public const int ADD_RESPONSE
= 9;
427 /// <summary> A delete request operation.
431 public const int DEL_REQUEST
= 10;
433 /// <summary> A delete response operation.
437 public const int DEL_RESPONSE
= 11;
439 /// <summary> A modify RDN request operation.
441 /// MODIFY_RDN_REQUEST = 12
443 public const int MODIFY_RDN_REQUEST
= 12;
445 /// <summary> A modify RDN response operation.
447 /// MODIFY_RDN_RESPONSE = 13
449 public const int MODIFY_RDN_RESPONSE
= 13;
451 /// <summary> A compare result operation.
453 /// COMPARE_REQUEST = 14
455 public const int COMPARE_REQUEST
= 14;
457 /// <summary> A compare response operation.
459 /// COMPARE_RESPONSE = 15
461 public const int COMPARE_RESPONSE
= 15;
463 /// <summary> An abandon request operation.
465 /// ABANDON_REQUEST = 16
467 public const int ABANDON_REQUEST
= 16;
470 /// <summary> A search result reference operation.
472 /// SEARCH_RESULT_REFERENCE = 19
474 public const int SEARCH_RESULT_REFERENCE
= 19;
476 /// <summary> An extended request operation.
478 /// EXTENDED_REQUEST = 23
480 public const int EXTENDED_REQUEST
= 23;
482 /// <summary> An extended response operation.
484 /// EXTENDED_RESONSE = 24
486 public const int EXTENDED_RESPONSE
= 24;
488 /// <summary> A request or response message for an asynchronous Ldap operation.</summary>
489 protected internal RfcLdapMessage message
;
491 /// <summary> Lock object to protect counter for message numbers</summary>
493 private static Object msgLock = new Object();
496 /// <summary> Counters used to construct request message #'s, unique for each request
497 /// Will be enabled after ASN.1 conversion
500 private static int msgNum = 0; // Ldap Request counter
502 private int imsgNum
= - 1; // This instance LdapMessage number
504 private int messageType
= - 1;
506 /* application defined tag to identify this message */
507 private System
.String stringTag
= null;
509 /// <summary> Dummy constuctor</summary>
511 internal LdapMessage()
516 /// <summary> Creates an LdapMessage when sending a protocol operation and sends
517 /// some optional controls with the message.
520 /// <param name="op">The operation type of message.
523 /// <param name="controls">The controls to use with the operation.
526 /// <seealso cref="Type">
529 internal LdapMessage(int type
, RfcRequest op
, LdapControl
[] controls
)
532 // Get a unique number for this request message
535 RfcControls asn1Ctrls
= null;
536 if (controls
!= null)
538 // Move LdapControls into an RFC 2251 Controls object.
539 asn1Ctrls
= new RfcControls();
540 for (int i
= 0; i
< controls
.Length
; i
++)
542 // asn1Ctrls.add(null);
543 asn1Ctrls
.add(controls
[i
].Asn1Object
);
547 // create RFC 2251 LdapMessage
548 message
= new RfcLdapMessage(op
, asn1Ctrls
);
552 /// <summary> Creates an Rfc 2251 LdapMessage when the libraries receive a response
556 /// <param name="message">A response message.
558 protected internal LdapMessage(RfcLdapMessage message
)
560 this.message
= message
;
564 /// <summary> Returns a mutated clone of this LdapMessage,
565 /// replacing base dn, filter.
568 /// <param name="dn">the base dn
571 /// <param name="filter">the filter
574 /// <param name="reference">true if a search reference
577 /// <returns> the object representing the new message
580 internal LdapMessage
Clone(System
.String dn
, System
.String filter
, bool reference
)
582 return new LdapMessage((RfcLdapMessage
) message
.dupMessage(dn
, filter
, reference
));
585 /// <summary> Instantiates an LdapControl. We search through our list of
586 /// registered controls. If we find a matchiing OID we instantiate
587 /// that control by calling its contructor. Otherwise we default to
588 /// returning a regular LdapControl object
591 private LdapControl
controlFactory(System
.String oid
, bool critical
, sbyte[] value_Renamed
)
593 // throw new NotImplementedException();
594 RespControlVector regControls
= LdapControl
.RegisteredControls
;
598 * search through the registered extension list to find the
599 * response control class
601 System
.Type respCtlClass
= regControls
.findResponseControl(oid
);
603 // Did not find a match so return default LDAPControl
604 if (respCtlClass
== null)
605 return new LdapControl(oid
, critical
, value_Renamed
);
607 /* If found, get LDAPControl constructor */
608 System
.Type
[] argsClass
= new System
.Type
[]{typeof(System.String), typeof(bool), typeof(sbyte[])}
;
609 System
.Object
[] args
= new System
.Object
[]{oid, critical, value_Renamed}
;
610 System
.Exception ex
= null;
613 System
.Reflection
.ConstructorInfo ctlConstructor
= respCtlClass
.GetConstructor(argsClass
);
617 /* Call the control constructor for a registered Class*/
618 System
.Object ctl
= null;
619 // ctl = ctlConstructor.newInstance(args);
620 ctl
= ctlConstructor
.Invoke(args
);
621 return (LdapControl
) ctl
;
623 catch (System
.UnauthorizedAccessException e
)
627 catch (System
.Reflection
.TargetInvocationException e
)
631 catch (System
.Exception e
)
633 // Could not create the ResponseControl object
634 // All possible exceptions are ignored. We fall through
635 // and create a default LDAPControl object
640 catch (System
.MethodAccessException e
)
642 // bad class was specified, fall through and return a
643 // default LDAPControl object
647 catch (System
.FieldAccessException e
)
649 // No match with the OID
650 // Do nothing. Fall through and construct a default LDAPControl object.
652 // If we get here we did not have a registered response control
653 // for this oid. Return a default LDAPControl object.
654 return new LdapControl(oid
, critical
, value_Renamed
);
658 /// <summary> Creates a String representation of this object
661 /// <returns> a String representation for this LdapMessage
663 public override System
.String
ToString()
665 return Name
+ "(" + MessageID
+ "): " + message
.ToString();