Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / LdapMessage.cs
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc.  www.novell.com
4
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:
11
12 * The above copyright notice and this permission notice shall be included in 
13 * all copies or substantial portions of the Software.
14
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
21 * SOFTWARE.
22 *******************************************************************************/
23 //
24 // Novell.Directory.Ldap.LdapMessage.cs
25 //
26 // Author:
27 //   Sunil Kumar (Sunilk@novell.com)
28 //
29 // (C) 2003 Novell, Inc (http://www.novell.com)
30 //
31
32 using System;
33 using Novell.Directory.Ldap.Rfc2251;
34 using Novell.Directory.Ldap.Asn1;
35 using Novell.Directory.Ldap.Utilclass;
36
37 namespace Novell.Directory.Ldap
38 {
39         
40         /// <summary> The base class for Ldap request and response messages.
41         /// 
42         /// Subclassed by response messages used in asynchronous operations.
43         /// 
44         /// 
45         /// </summary>
46         public class LdapMessage
47         {
48                 /// <summary> Returns the LdapMessage request associated with this response</summary>
49                 virtual internal LdapMessage RequestingMessage
50                 {
51                         /* package */
52                         
53                         get
54                         {
55                                 return message.RequestingMessage;
56                         }
57                         
58                 }
59                 /// <summary> Returns any controls in the message.</summary>
60                 virtual public LdapControl[] Controls
61                 {
62                         get
63                         {
64                                 
65 /*                              LdapControl[] controls = null;
66                                 RfcControls asn1Ctrls = message.Controls;
67                                 
68                                 if (asn1Ctrls != null)
69                                 {
70                                         controls = new LdapControl[asn1Ctrls.size()];
71                                         for (int i = 0; i < asn1Ctrls.size(); i++)
72                                         {
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();
77                                                 
78                                                 controls[i] = controlFactory(oid, critical, value_Renamed);
79                                         }
80                                 }
81
82                                 return controls;
83 */
84                                 LdapControl[] controls = null;
85                                 RfcControls asn1Ctrls = message.Controls;
86                                 
87                                 // convert from RFC 2251 Controls to LDAPControl[].
88                                 if (asn1Ctrls != null)
89                                 {
90                                         controls = new LdapControl[asn1Ctrls.size()];
91                                         for (int i = 0; i < asn1Ctrls.size(); i++)
92                                         {
93                                                 
94                                                 /*
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.
102                                                 *
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.
106                                                 */
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();
111                                                 
112                                                 /* Return from this call should return either an LDAPControl
113                                                 * or a class extending LDAPControl that implements the
114                                                 * appropriate registered response control
115                                                 */
116                                                 controls[i] = controlFactory(oid, critical, value_Renamed);
117                                         }
118                                 }
119                                 return controls;
120
121                         }
122                         
123                 }
124
125                 /// <summary> Returns the message ID.  The message ID is an integer value
126                 /// identifying the Ldap request and its response.
127                 /// </summary>
128                 virtual public int MessageID
129                 {
130                         get
131                         {
132                                 if (imsgNum == - 1)
133                                 {
134                                         imsgNum = message.MessageID;
135                                 }
136                                 return imsgNum;
137                         }
138                         
139                 }
140                 /// <summary> Returns the Ldap operation type of the message.
141                 /// 
142                 /// The type is one of the following:
143                 /// <ul>
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>
165                 /// </ul>
166                 /// 
167                 /// </summary>
168                 /// <returns> The operation type of the message.
169                 /// </returns>
170                 virtual public int Type
171                 {
172                         get
173                         {
174                                 if (messageType == - 1)
175                                 {
176                                         messageType = message.Type;
177                                 }
178                                 return messageType;
179                         }
180                         
181                 }
182                 /// <summary> Indicates whether the message is a request or a response
183                 /// 
184                 /// </summary>
185                 /// <returns> true if the message is a request, false if it is a response,
186                 /// a search result, or a search result reference.
187                 /// </returns>
188                 virtual public bool Request
189                 {
190                         get
191                         {
192                                 return message.isRequest();
193                         }
194                         
195                 }
196                 /// <summary> Returns the RFC 2251 LdapMessage composed in this object.</summary>
197                 virtual internal RfcLdapMessage Asn1Object
198                 {
199                         /* package */
200                         
201                         get
202                         {
203                                 return message;
204                         }
205                         
206                 }
207                 private System.String Name
208                 {
209                         get
210                         {
211                                 System.String name;
212                                 switch (Type)
213                                 {
214                                         
215                                         case SEARCH_RESPONSE: 
216                                                 name = "LdapSearchResponse";
217                                                 break;
218                                         
219                                         case SEARCH_RESULT: 
220                                                 name = "LdapSearchResult";
221                                                 break;
222                                         
223                                         case SEARCH_REQUEST: 
224                                                 name = "LdapSearchRequest";
225                                                 break;
226                                         
227                                         case MODIFY_REQUEST: 
228                                                 name = "LdapModifyRequest";
229                                                 break;
230                                         
231                                         case MODIFY_RESPONSE: 
232                                                 name = "LdapModifyResponse";
233                                                 break;
234                                         
235                                         case ADD_REQUEST: 
236                                                 name = "LdapAddRequest";
237                                                 break;
238                                         
239                                         case ADD_RESPONSE: 
240                                                 name = "LdapAddResponse";
241                                                 break;
242                                         
243                                         case DEL_REQUEST: 
244                                                 name = "LdapDelRequest";
245                                                 break;
246                                         
247                                         case DEL_RESPONSE: 
248                                                 name = "LdapDelResponse";
249                                                 break;
250                                         
251                                         case MODIFY_RDN_REQUEST: 
252                                                 name = "LdapModifyRDNRequest";
253                                                 break;
254                                         
255                                         case MODIFY_RDN_RESPONSE: 
256                                                 name = "LdapModifyRDNResponse";
257                                                 break;
258                                         
259                                         case COMPARE_REQUEST: 
260                                                 name = "LdapCompareRequest";
261                                                 break;
262                                         
263                                         case COMPARE_RESPONSE: 
264                                                 name = "LdapCompareResponse";
265                                                 break;
266                                         
267                                         case BIND_REQUEST: 
268                                                 name = "LdapBindRequest";
269                                                 break;
270                                         
271                                         case BIND_RESPONSE: 
272                                                 name = "LdapBindResponse";
273                                                 break;
274                                         
275                                         case UNBIND_REQUEST: 
276                                                 name = "LdapUnbindRequest";
277                                                 break;
278                                         
279                                         case ABANDON_REQUEST: 
280                                                 name = "LdapAbandonRequest";
281                                                 break;
282                                         
283                                         case SEARCH_RESULT_REFERENCE: 
284                                                 name = "LdapSearchResultReference";
285                                                 break;
286                                         
287                                         case EXTENDED_REQUEST: 
288                                                 name = "LdapExtendedRequest";
289                                                 break;
290                                         
291                                         case EXTENDED_RESPONSE: 
292                                                 name = "LdapExtendedResponse";
293                                                 break;
294
295                                         case INTERMEDIATE_RESPONSE:
296                                                 name = "LdapIntermediateResponse";
297                                                 break;
298                                         
299                                         default: 
300                                                 throw new System.SystemException("LdapMessage: Unknown Type " + Type);
301                                         
302                                 }
303                                 return name;
304                         }
305                         
306                 }
307                 /// <summary> Retrieves the identifier tag for this message.
308                 /// 
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.
314                 /// 
315                 /// </summary>
316                 /// <returns> the identifier associated with this message or <code>null</code>
317                 /// if none.
318                 /// 
319                 /// </returns>
320                 /// <summary> Sets a string identifier tag for this message.
321                 /// 
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
326                 /// from the server.
327                 /// 
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.
333                 /// 
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.
339                 /// 
340                 /// </summary>
341                 /// <param name="stringTag"> the String assigned to identify this message.
342                 /// 
343                 /// </param>
344                 virtual public System.String Tag
345                 {
346                         get
347                         {
348                                 if ((System.Object) this.stringTag != null)
349                                 {
350                                         return this.stringTag;
351                                 }
352                                 if (Request)
353                                 {
354                                         return null;
355                                 }
356                                 LdapMessage m = this.RequestingMessage;
357                                 if (m == null)
358                                 {
359                                         return null;
360                                 }
361                                 return m.stringTag;
362                         }
363                         
364                         set
365                         {
366                                 this.stringTag = value;
367                                 return ;
368                         }
369                         
370                 }
371                 
372                 /// <summary> A bind request operation.
373                 /// 
374                 /// BIND_REQUEST = 0
375                 /// </summary>
376                 public const int BIND_REQUEST = 0;
377                 
378                 /// <summary> A bind response operation.
379                 /// 
380                 /// BIND_RESPONSE = 1
381                 /// </summary>
382                 public const int BIND_RESPONSE = 1;
383                 
384                 /// <summary> An unbind request operation.
385                 /// 
386                 /// UNBIND_REQUEST = 2
387                 /// </summary>
388                 public const int UNBIND_REQUEST = 2;
389                 
390                 /// <summary> A search request operation.
391                 /// 
392                 /// SEARCH_REQUEST = 3
393                 /// </summary>
394                 public const int SEARCH_REQUEST = 3;
395                 
396                 /// <summary> A search response containing data.
397                 /// 
398                 /// SEARCH_RESPONSE = 4
399                 /// </summary>
400                 public const int SEARCH_RESPONSE = 4;
401                 
402                 /// <summary> A search result message - contains search status.
403                 /// 
404                 /// SEARCH_RESULT = 5
405                 /// </summary>
406                 public const int SEARCH_RESULT = 5;
407                 
408                 /// <summary> A modify request operation.
409                 /// 
410                 /// MODIFY_REQUEST = 6
411                 /// </summary>
412                 public const int MODIFY_REQUEST = 6;
413                 
414                 /// <summary> A modify response operation.
415                 /// 
416                 /// MODIFY_RESPONSE = 7
417                 /// </summary>
418                 public const int MODIFY_RESPONSE = 7;
419                 
420                 /// <summary> An add request operation.
421                 /// 
422                 /// ADD_REQUEST = 8
423                 /// </summary>
424                 public const int ADD_REQUEST = 8;
425                 
426                 /// <summary> An add response operation.
427                 /// 
428                 /// ADD_RESONSE = 9
429                 /// </summary>
430                 public const int ADD_RESPONSE = 9;
431                 
432                 /// <summary> A delete request operation.
433                 /// 
434                 /// DEL_REQUEST = 10
435                 /// </summary>
436                 public const int DEL_REQUEST = 10;
437                 
438                 /// <summary> A delete response operation.
439                 /// 
440                 /// DEL_RESONSE = 11
441                 /// </summary>
442                 public const int DEL_RESPONSE = 11;
443                 
444                 /// <summary> A modify RDN request operation.
445                 /// 
446                 /// MODIFY_RDN_REQUEST = 12
447                 /// </summary>
448                 public const int MODIFY_RDN_REQUEST = 12;
449                 
450                 /// <summary> A modify RDN response operation.
451                 /// 
452                 /// MODIFY_RDN_RESPONSE = 13
453                 /// </summary>
454                 public const int MODIFY_RDN_RESPONSE = 13;
455                 
456                 /// <summary> A compare result operation.
457                 /// 
458                 /// COMPARE_REQUEST = 14
459                 /// </summary>
460                 public const int COMPARE_REQUEST = 14;
461                 
462                 /// <summary> A compare response operation.
463                 /// 
464                 /// COMPARE_RESPONSE = 15
465                 /// </summary>
466                 public const int COMPARE_RESPONSE = 15;
467                 
468                 /// <summary> An abandon request operation.
469                 /// 
470                 /// ABANDON_REQUEST = 16
471                 /// </summary>
472                 public const int ABANDON_REQUEST = 16;
473                 
474                 
475                 /// <summary> A search result reference operation.
476                 /// 
477                 /// SEARCH_RESULT_REFERENCE = 19
478                 /// </summary>
479                 public const int SEARCH_RESULT_REFERENCE = 19;
480                 
481                 /// <summary> An extended request operation.
482                 /// 
483                 /// EXTENDED_REQUEST = 23
484                 /// </summary>
485                 public const int EXTENDED_REQUEST = 23;
486                 
487                 /// <summary> An extended response operation.
488                 /// 
489                 /// EXTENDED_RESONSE = 24
490                 /// </summary>
491                 public const int EXTENDED_RESPONSE = 24;
492
493                 /// <summary> An intermediate response operation.
494                 /// 
495                 /// INTERMEDIATE_RESONSE = 25
496                 /// </summary>
497                 public const int INTERMEDIATE_RESPONSE = 25;
498
499                 /// <summary> A request or response message for an asynchronous Ldap operation.</summary>
500                 protected internal RfcLdapMessage message;
501                 
502                 /// <summary> Lock object to protect counter for message numbers</summary>
503                 /*
504                 private static Object msgLock = new Object();
505                 */
506                 
507                 /// <summary> Counters used to construct request message #'s, unique for each request
508                 /// Will be enabled after ASN.1 conversion
509                 /// </summary>
510                 /*
511                 private static int msgNum = 0; // Ldap Request counter
512                 */
513                 private int imsgNum = - 1; // This instance LdapMessage number
514                 
515                 private int messageType = - 1;
516                 
517                 /* application defined tag to identify this message */
518                 private System.String stringTag = null;
519                 
520                 /// <summary> Dummy constuctor</summary>
521                 /* package */
522                 internal LdapMessage()
523                 {
524                         return ;
525                 }
526                 
527                 /// <summary> Creates an LdapMessage when sending a protocol operation and sends
528                 /// some optional controls with the message.
529                 /// 
530                 /// </summary>
531                 /// <param name="op">The operation type of message.
532                 /// 
533                 /// </param>
534                 /// <param name="controls">The controls to use with the operation.
535                 /// 
536                 /// </param>
537                 /// <seealso cref="Type">
538                 /// </seealso>
539                 /*package*/
540                 internal LdapMessage(int type, RfcRequest op, LdapControl[] controls)
541                 {
542                         
543                         // Get a unique number for this request message
544                         
545                         messageType = type;
546                         RfcControls asn1Ctrls = null;
547                         if (controls != null)
548                         {
549                                 // Move LdapControls into an RFC 2251 Controls object.
550                                 asn1Ctrls = new RfcControls();
551                                 for (int i = 0; i < controls.Length; i++)
552                                 {
553 //                                      asn1Ctrls.add(null);
554                                         asn1Ctrls.add(controls[i].Asn1Object);
555                                 }
556                         }
557                         
558                         // create RFC 2251 LdapMessage
559                         message = new RfcLdapMessage(op, asn1Ctrls);
560                         return ;
561                 }
562                 
563                 /// <summary> Creates an Rfc 2251 LdapMessage when the libraries receive a response
564                 /// from a command.
565                 /// 
566                 /// </summary>
567                 /// <param name="message">A response message.
568                 /// </param>
569                 protected internal LdapMessage(RfcLdapMessage message)
570                 {
571                         this.message = message;
572                         return ;
573                 }
574                 
575                 /// <summary> Returns a mutated clone of this LdapMessage,
576                 /// replacing base dn, filter.
577                 /// 
578                 /// </summary>
579                 /// <param name="dn">the base dn
580                 /// 
581                 /// </param>
582                 /// <param name="filter">the filter
583                 /// 
584                 /// </param>
585                 /// <param name="reference">true if a search reference
586                 /// 
587                 /// </param>
588                 /// <returns> the object representing the new message
589                 /// </returns>
590                 /* package */
591                 internal LdapMessage Clone(System.String dn, System.String filter, bool reference)
592                 {
593                         return new LdapMessage((RfcLdapMessage) message.dupMessage(dn, filter, reference));
594                 }
595                 
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
600                 /// 
601                 /// </summary>
602                 private LdapControl controlFactory(System.String oid, bool critical, sbyte[] value_Renamed)
603                 {
604 //                      throw new NotImplementedException();
605                         RespControlVector regControls = LdapControl.RegisteredControls;
606                         try
607                         {
608                                 /*
609                                 * search through the registered extension list to find the
610                                 * response control class
611                                 */
612                                 System.Type respCtlClass = regControls.findResponseControl(oid);
613                                 
614                                 // Did not find a match so return default LDAPControl
615                                 if (respCtlClass == null)
616                                         return new LdapControl(oid, critical, value_Renamed);
617                                 
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;
622                                 try
623                                 {
624                                         System.Reflection.ConstructorInfo ctlConstructor = respCtlClass.GetConstructor(argsClass);
625                                         
626                                         try
627                                         {
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;
633                                         }
634                                         catch (System.UnauthorizedAccessException e)
635                                         {
636                                                 ex = e;
637                                         }
638                                         catch (System.Reflection.TargetInvocationException e)
639                                         {
640                                                 ex = e;
641                                         }
642                                         catch (System.Exception e)
643                                         {
644                                                 // Could not create the ResponseControl object
645                                                 // All possible exceptions are ignored. We fall through
646                                                 // and create a default LDAPControl object
647                                                 ex = e;
648                                         }
649
650                                 }
651                                 catch (System.MethodAccessException e)
652                                 {
653                                         // bad class was specified, fall through and return a
654                                         // default LDAPControl object
655                                         ex = e;
656                                 }
657                         }
658                         catch (System.FieldAccessException e)
659                         {
660                                 // No match with the OID
661                                 // Do nothing. Fall through and construct a default LDAPControl object.
662                         }
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);
666
667                 }
668                 
669                 /// <summary> Creates a String representation of this object
670                 /// 
671                 /// </summary>
672                 /// <returns> a String representation for this LdapMessage
673                 /// </returns>
674                 public override System.String ToString()
675                 {
676                         return Name + "(" + MessageID + "): " + message.ToString();
677                 }
678         }
679 }