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>
164 /// <li>INTERMEDIATE_RESPONSE = 25;</li>
168 /// <returns> The operation type of the message.
170 virtual public int Type
174 if (messageType == - 1)
176 messageType = message.Type;
182 /// <summary> Indicates whether the message is a request or a response
185 /// <returns> true if the message is a request, false if it is a response,
186 /// a search result, or a search result reference.
188 virtual public bool Request
192 return message.isRequest();
196 /// <summary> Returns the RFC 2251 LdapMessage composed in this object.</summary>
197 virtual internal RfcLdapMessage Asn1Object
207 private System.String Name
215 case SEARCH_RESPONSE:
216 name = "LdapSearchResponse";
220 name = "LdapSearchResult";
224 name = "LdapSearchRequest";
228 name = "LdapModifyRequest";
231 case MODIFY_RESPONSE:
232 name = "LdapModifyResponse";
236 name = "LdapAddRequest";
240 name = "LdapAddResponse";
244 name = "LdapDelRequest";
248 name = "LdapDelResponse";
251 case MODIFY_RDN_REQUEST:
252 name = "LdapModifyRDNRequest";
255 case MODIFY_RDN_RESPONSE:
256 name = "LdapModifyRDNResponse";
259 case COMPARE_REQUEST:
260 name = "LdapCompareRequest";
263 case COMPARE_RESPONSE:
264 name = "LdapCompareResponse";
268 name = "LdapBindRequest";
272 name = "LdapBindResponse";
276 name = "LdapUnbindRequest";
279 case ABANDON_REQUEST:
280 name = "LdapAbandonRequest";
283 case SEARCH_RESULT_REFERENCE:
284 name = "LdapSearchResultReference";
287 case EXTENDED_REQUEST:
288 name = "LdapExtendedRequest";
291 case EXTENDED_RESPONSE:
292 name = "LdapExtendedResponse";
295 case INTERMEDIATE_RESPONSE:
296 name = "LdapIntermediateResponse";
300 throw new System.SystemException("LdapMessage: Unknown Type " + Type);
307 /// <summary> Retrieves the identifier tag for this message.
309 /// An identifier can be associated with a message with the
310 /// <code>setTag</code> method.
311 /// Tags are set by the application and not by the API or the server.
312 /// If a server response <code>isRequest() == false</code> has no tag,
313 /// the tag associated with the corresponding server request is used.
316 /// <returns> the identifier associated with this message or <code>null</code>
320 /// <summary> Sets a string identifier tag for this message.
322 /// This method allows an API to set a tag and later identify messages
323 /// by retrieving the tag associated with the message.
324 /// Tags are set by the application and not by the API or the server.
325 /// Message tags are not included with any message sent to or received
328 /// Tags set on a request to the server
329 /// are automatically associated with the response messages when they are
330 /// received by the API and transferred to the application.
331 /// The application can explicitly set a different value in a
332 /// response message.
334 /// To set a value in a server request, for example an
335 /// {@link LdapSearchRequest}, you must create the object,
336 /// set the tag, and use the
337 /// {@link LdapConnection.SendRequest LdapConnection.sendRequest()}
338 /// method to send it to the server.
341 /// <param name="stringTag"> the String assigned to identify this message.
344 virtual public System.String Tag
348 if ((System.Object) this.stringTag != null)
350 return this.stringTag;
356 LdapMessage m = this.RequestingMessage;
366 this.stringTag = value;
372 /// <summary> A bind request operation.
376 public const int BIND_REQUEST = 0;
378 /// <summary> A bind response operation.
380 /// BIND_RESPONSE = 1
382 public const int BIND_RESPONSE = 1;
384 /// <summary> An unbind request operation.
386 /// UNBIND_REQUEST = 2
388 public const int UNBIND_REQUEST = 2;
390 /// <summary> A search request operation.
392 /// SEARCH_REQUEST = 3
394 public const int SEARCH_REQUEST = 3;
396 /// <summary> A search response containing data.
398 /// SEARCH_RESPONSE = 4
400 public const int SEARCH_RESPONSE = 4;
402 /// <summary> A search result message - contains search status.
404 /// SEARCH_RESULT = 5
406 public const int SEARCH_RESULT = 5;
408 /// <summary> A modify request operation.
410 /// MODIFY_REQUEST = 6
412 public const int MODIFY_REQUEST = 6;
414 /// <summary> A modify response operation.
416 /// MODIFY_RESPONSE = 7
418 public const int MODIFY_RESPONSE = 7;
420 /// <summary> An add request operation.
424 public const int ADD_REQUEST = 8;
426 /// <summary> An add response operation.
430 public const int ADD_RESPONSE = 9;
432 /// <summary> A delete request operation.
436 public const int DEL_REQUEST = 10;
438 /// <summary> A delete response operation.
442 public const int DEL_RESPONSE = 11;
444 /// <summary> A modify RDN request operation.
446 /// MODIFY_RDN_REQUEST = 12
448 public const int MODIFY_RDN_REQUEST = 12;
450 /// <summary> A modify RDN response operation.
452 /// MODIFY_RDN_RESPONSE = 13
454 public const int MODIFY_RDN_RESPONSE = 13;
456 /// <summary> A compare result operation.
458 /// COMPARE_REQUEST = 14
460 public const int COMPARE_REQUEST = 14;
462 /// <summary> A compare response operation.
464 /// COMPARE_RESPONSE = 15
466 public const int COMPARE_RESPONSE = 15;
468 /// <summary> An abandon request operation.
470 /// ABANDON_REQUEST = 16
472 public const int ABANDON_REQUEST = 16;
475 /// <summary> A search result reference operation.
477 /// SEARCH_RESULT_REFERENCE = 19
479 public const int SEARCH_RESULT_REFERENCE = 19;
481 /// <summary> An extended request operation.
483 /// EXTENDED_REQUEST = 23
485 public const int EXTENDED_REQUEST = 23;
487 /// <summary> An extended response operation.
489 /// EXTENDED_RESONSE = 24
491 public const int EXTENDED_RESPONSE = 24;
493 /// <summary> An intermediate response operation.
495 /// INTERMEDIATE_RESONSE = 25
497 public const int INTERMEDIATE_RESPONSE = 25;
499 /// <summary> A request or response message for an asynchronous Ldap operation.</summary>
500 protected internal RfcLdapMessage message;
502 /// <summary> Lock object to protect counter for message numbers</summary>
504 private static Object msgLock = new Object();
507 /// <summary> Counters used to construct request message #'s, unique for each request
508 /// Will be enabled after ASN.1 conversion
511 private static int msgNum = 0; // Ldap Request counter
513 private int imsgNum = - 1; // This instance LdapMessage number
515 private int messageType = - 1;
517 /* application defined tag to identify this message */
518 private System.String stringTag = null;
520 /// <summary> Dummy constuctor</summary>
522 internal LdapMessage()
527 /// <summary> Creates an LdapMessage when sending a protocol operation and sends
528 /// some optional controls with the message.
531 /// <param name="op">The operation type of message.
534 /// <param name="controls">The controls to use with the operation.
537 /// <seealso cref="Type">
540 internal LdapMessage(int type, RfcRequest op, LdapControl[] controls)
543 // Get a unique number for this request message
546 RfcControls asn1Ctrls = null;
547 if (controls != null)
549 // Move LdapControls into an RFC 2251 Controls object.
550 asn1Ctrls = new RfcControls();
551 for (int i = 0; i < controls.Length; i++)
553 // asn1Ctrls.add(null);
554 asn1Ctrls.add(controls[i].Asn1Object);
558 // create RFC 2251 LdapMessage
559 message = new RfcLdapMessage(op, asn1Ctrls);
563 /// <summary> Creates an Rfc 2251 LdapMessage when the libraries receive a response
567 /// <param name="message">A response message.
569 protected internal LdapMessage(RfcLdapMessage message)
571 this.message = message;
575 /// <summary> Returns a mutated clone of this LdapMessage,
576 /// replacing base dn, filter.
579 /// <param name="dn">the base dn
582 /// <param name="filter">the filter
585 /// <param name="reference">true if a search reference
588 /// <returns> the object representing the new message
591 internal LdapMessage Clone(System.String dn, System.String filter, bool reference)
593 return new LdapMessage((RfcLdapMessage) message.dupMessage(dn, filter, reference));
596 /// <summary> Instantiates an LdapControl. We search through our list of
597 /// registered controls. If we find a matchiing OID we instantiate
598 /// that control by calling its contructor. Otherwise we default to
599 /// returning a regular LdapControl object
602 private LdapControl controlFactory(System.String oid, bool critical, sbyte[] value_Renamed)
604 // throw new NotImplementedException();
605 RespControlVector regControls = LdapControl.RegisteredControls;
609 * search through the registered extension list to find the
610 * response control class
612 System.Type respCtlClass = regControls.findResponseControl(oid);
614 // Did not find a match so return default LDAPControl
615 if (respCtlClass == null)
616 return new LdapControl(oid, critical, value_Renamed);
618 /* If found, get LDAPControl constructor */
619 System.Type[] argsClass = new System.Type[]{typeof(System.String), typeof(bool), typeof(sbyte[])};
620 System.Object[] args = new System.Object[]{oid, critical, value_Renamed};
621 System.Exception ex = null;
624 System.Reflection.ConstructorInfo ctlConstructor = respCtlClass.GetConstructor(argsClass);
628 /* Call the control constructor for a registered Class*/
629 System.Object ctl = null;
630 // ctl = ctlConstructor.newInstance(args);
631 ctl = ctlConstructor.Invoke(args);
632 return (LdapControl) ctl;
634 catch (System.UnauthorizedAccessException e)
638 catch (System.Reflection.TargetInvocationException e)
642 catch (System.Exception e)
644 // Could not create the ResponseControl object
645 // All possible exceptions are ignored. We fall through
646 // and create a default LDAPControl object
651 catch (System.MethodAccessException e)
653 // bad class was specified, fall through and return a
654 // default LDAPControl object
658 catch (System.FieldAccessException e)
660 // No match with the OID
661 // Do nothing. Fall through and construct a default LDAPControl object.
663 // If we get here we did not have a registered response control
664 // for this oid. Return a default LDAPControl object.
665 return new LdapControl(oid, critical, value_Renamed);
669 /// <summary> Creates a String representation of this object
672 /// <returns> a String representation for this LdapMessage
674 public override System.String ToString()
676 return Name + "(" + MessageID + "): " + message.ToString();