Added Support for Schema operation
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / LdapUrl.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.LdapUrl.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 ArrayEnumeration = Novell.Directory.Ldap.Utilclass.ArrayEnumeration;
34
35 namespace Novell.Directory.Ldap
36 {
37         
38         /// <summary> 
39         /// Encapsulates parameters of an Ldap URL query as defined in RFC2255.
40         /// 
41         /// An LdapUrl object can be passed to LdapConnection.search to retrieve
42         /// search results.
43         /// 
44         /// </summary>
45         /// <seealso cref="LdapConnection#search">
46         /// </seealso>
47         public class LdapUrl : System.ICloneable
48         {
49                 private void  InitBlock()
50                 {
51                         scope = DEFAULT_SCOPE;
52                 }
53                 /// <summary> Returns an array of attribute names specified in the URL.
54                 /// 
55                 /// </summary>
56                 /// <returns> An array of attribute names in the URL.
57                 /// </returns>
58                 virtual public System.String[] AttributeArray
59                 {
60                         get
61                         {
62                                 return attrs;
63                         }
64                         
65                 }
66                 /// <summary> Returns an enumerator for the attribute names specified in the URL.
67                 /// 
68                 /// </summary>
69                 /// <returns> An enumeration of attribute names.
70                 /// </returns>
71                 virtual public System.Collections.IEnumerator Attributes
72                 {
73                         get
74                         {
75                                 return new ArrayEnumeration(attrs);
76                         }
77                         
78                 }
79                 /// <summary> Returns any Ldap URL extensions specified, or null if none are
80                 /// specified. Each extension is a type=value expression. The =value part
81                 /// MAY be omitted. The expression MAY be prefixed with '!' if it is
82                 /// mandatory for evaluation of the URL.
83                 /// 
84                 /// </summary>
85                 /// <returns> string array of extensions.
86                 /// </returns>
87                 virtual public System.String[] Extensions
88                 {
89                         get
90                         {
91                                 return extensions;
92                         }
93                         
94                 }
95                 /// <summary> Returns the search filter or <code>null</code> if none was specified.
96                 /// 
97                 /// </summary>
98                 /// <returns> The search filter.
99                 /// </returns>
100                 virtual public System.String Filter
101                 {
102                         get
103                         {
104                                 return filter;
105                         }
106                         
107                 }
108                 /// <summary> Returns the name of the Ldap server in the URL.
109                 /// 
110                 /// </summary>
111                 /// <returns> The host name specified in the URL.
112                 /// </returns>
113                 virtual public System.String Host
114                 {
115                         get
116                         {
117                                 return host;
118                         }
119                         
120                 }
121                 /// <summary> Returns the port number of the Ldap server in the URL.
122                 /// 
123                 /// </summary>
124                 /// <returns> The port number in the URL.
125                 /// </returns>
126                 virtual public int Port
127                 {
128                         get
129                         {
130                                 if (port == 0)
131                                 {
132                                         return LdapConnection.DEFAULT_PORT;
133                                 }
134                                 return port;
135                         }
136                         
137                 }
138                 /// <summary> Returns the depth of search. It returns one of the following from
139                 /// LdapConnection: SCOPE_BASE, SCOPE_ONE, or SCOPE_SUB.
140                 /// 
141                 /// </summary>
142                 /// <returns> The search scope.
143                 /// </returns>
144                 virtual public int Scope
145                 {
146                         get
147                         {
148                                 return scope;
149                         }
150                         
151                 }
152                 /// <summary> Returns true if the URL is of the type ldaps (Ldap over SSL, a predecessor
153                 /// to startTls)
154                 /// 
155                 /// </summary>
156                 /// <returns> whether this is a secure Ldap url or not.
157                 /// </returns>
158                 virtual public bool Secure
159                 {
160                         get
161                         {
162                                 return secure;
163                         }
164                         
165                 }
166                 private static readonly int DEFAULT_SCOPE = LdapConnection.SCOPE_BASE;
167                 
168                 // Broken out parts of the URL
169                 private bool secure = false; // URL scheme ldap/ldaps
170                 private bool ipV6 = false; // TCP/IP V6
171                 private System.String host = null; // Host
172                 private int port = 0; // Port
173                 private System.String dn = null; // Base DN
174                 private System.String[] attrs = null; // Attributes
175                 private System.String filter = null; // Filter
176                 private int scope; // Scope
177                 private System.String[] extensions = null; // Extensions
178                 
179                 /// <summary> Constructs a URL object with the specified string as the URL.
180                 /// 
181                 /// </summary>
182                 /// <param name="url">     An Ldap URL string, e.g.
183                 /// "ldap://ldap.example.com:80/dc=example,dc=com?cn,
184                 /// sn?sub?(objectclass=inetOrgPerson)".
185                 /// 
186                 /// </param>
187                 /// <exception cref=""> MalformedURLException The specified URL cannot be parsed.
188                 /// </exception>
189                 public LdapUrl(System.String url)
190                 {
191                         InitBlock();
192                         parseURL(url);
193                         return ;
194                 }
195                 
196                 
197                 /// <summary> Constructs a URL object with the specified host, port, and DN.
198                 /// 
199                 /// <p>This form is used to create URL references to a particular object
200                 /// in the directory.</p>
201                 /// 
202                 /// </summary>
203                 /// <param name="host">    Host identifier of Ldap server, or null for
204                 /// "localhost".
205                 /// <br><br>
206                 /// </param>
207                 /// <param name="port">    The port number for Ldap server (use
208                 /// LdapConnection.DEFAULT_PORT for default port).
209                 /// <br><br>
210                 /// </param>
211                 /// <param name="dn">      Distinguished name of the base object of the search.
212                 /// 
213                 /// </param>
214                 public LdapUrl(System.String host, int port, System.String dn)
215                 {
216                         InitBlock();
217                         this.host = host;
218                         this.port = port;
219                         this.dn = dn;
220                         return ;
221                 }
222                 
223                 /// <summary> Constructs an Ldap URL with all fields explicitly assigned, to
224                 /// specify an Ldap search operation.
225                 /// 
226                 /// </summary>
227                 /// <param name="host">    Host identifier of Ldap server, or null for
228                 /// "localhost".
229                 /// <br><br>
230                 /// </param>
231                 /// <param name="port">    The port number for Ldap server (use
232                 /// LdapConnection.DEFAULT_PORT for default port).
233                 /// <br><br>
234                 /// </param>
235                 /// <param name="dn">      Distinguished name of the base object of the search.
236                 /// 
237                 /// <br><br>
238                 /// </param>
239                 /// <param name="attrNames">Names or OIDs of attributes to retrieve.  Passing a
240                 /// null array signifies that all user attributes are to be
241                 /// retrieved. Passing a value of "*" allows you to specify
242                 /// that all user attributes as well as any specified
243                 /// operational attributes are to be retrieved.
244                 /// <br><br>
245                 /// 
246                 /// </param>
247                 /// <param name="scope">   Depth of search (in DN namespace). Use one of
248                 /// SCOPE_BASE, SCOPE_ONE, SCOPE_SUB from LdapConnection.
249                 /// <br><br>
250                 /// 
251                 /// </param>
252                 /// <param name="filter">  The search filter specifying the search criteria.
253                 /// <br><br>
254                 /// 
255                 /// </param>
256                 /// <param name="extensions"> Extensions provide a mechanism to extend the
257                 /// functionality of Ldap URLs. Currently no
258                 /// Ldap URL extensions are defined. Each extension
259                 /// specification is a type=value expression, and  may
260                 /// be <code>null</code> or empty.  The =value part may be
261                 /// omitted. The expression may be prefixed with '!' if it
262                 /// is mandatory for the evaluation of the URL.
263                 /// </param>
264                 public LdapUrl(System.String host, int port, System.String dn, System.String[] attrNames, int scope, System.String filter, System.String[] extensions)
265                 {
266                         InitBlock();
267                         this.host = host;
268                         this.port = port;
269                         this.dn = dn;
270                         this.attrs = new System.String[attrNames.Length];
271                         attrNames.CopyTo(this.attrs, 0);
272                         this.scope = scope;
273                         this.filter = filter;
274                         this.extensions = new System.String[extensions.Length];
275                         extensions.CopyTo(this.extensions, 0);
276                         return ;
277                 }
278                 
279                 /// <summary> Constructs an Ldap URL with all fields explicitly assigned, including
280                 /// isSecure, to specify an Ldap search operation.
281                 /// 
282                 /// </summary>
283                 /// <param name="host">    Host identifier of Ldap server, or null for
284                 /// "localhost".
285                 /// <br><br>
286                 /// 
287                 /// </param>
288                 /// <param name="port">    The port number for Ldap server (use
289                 /// LdapConnection.DEFAULT_PORT for default port).
290                 /// <br><br>
291                 /// 
292                 /// </param>
293                 /// <param name="dn">      Distinguished name of the base object of the search.
294                 /// <br><br>
295                 /// 
296                 /// </param>
297                 /// <param name="attrNames">Names or OIDs of attributes to retrieve.  Passing a
298                 /// null array signifies that all user attributes are to be
299                 /// retrieved. Passing a value of "*" allows you to specify
300                 /// that all user attributes as well as any specified
301                 /// operational attributes are to be retrieved.
302                 /// <br><br>
303                 /// 
304                 /// </param>
305                 /// <param name="scope">   Depth of search (in DN namespace). Use one of
306                 /// SCOPE_BASE, SCOPE_ONE, SCOPE_SUB from LdapConnection.
307                 /// <br><br>
308                 /// 
309                 /// </param>
310                 /// <param name="filter">  The search filter specifying the search criteria.
311                 /// from LdapConnection: SCOPE_BASE, SCOPE_ONE, SCOPE_SUB.
312                 /// <br><br>
313                 /// 
314                 /// </param>
315                 /// <param name="extensions"> Extensions provide a mechanism to extend the
316                 /// functionality of Ldap URLs. Currently no
317                 /// Ldap URL extensions are defined. Each extension
318                 /// specification is a type=value expression, and  may
319                 /// be <code>null</code> or empty.  The =value part may be
320                 /// omitted. The expression may be prefixed with '!' if it
321                 /// is mandatory for the evaluation of the URL.
322                 /// <br><br>
323                 /// 
324                 /// </param>
325                 /// <param name="secure">  If true creates an Ldap URL of the ldaps type
326                 /// </param>
327                 public LdapUrl(System.String host, int port, System.String dn, System.String[] attrNames, int scope, System.String filter, System.String[] extensions, bool secure)
328                 {
329                         InitBlock();
330                         this.host = host;
331                         this.port = port;
332                         this.dn = dn;
333                         this.attrs = attrNames;
334                         this.scope = scope;
335                         this.filter = filter;
336                         this.extensions = new System.String[extensions.Length];
337                         extensions.CopyTo(this.extensions, 0);
338                         this.secure = secure;
339                         return ;
340                 }
341                 
342                 /// <summary> Returns a clone of this URL object.
343                 /// 
344                 /// </summary>
345                 /// <returns> clone of this URL object.
346                 /// </returns>
347                 public System.Object Clone()
348                 {
349                         try
350                         {
351                                 return base.MemberwiseClone();
352                         }
353                         catch (System.Exception ce)
354                         {
355                                 throw new System.SystemException("Internal error, cannot create clone");
356                         }
357                 }
358                 
359                 /// <summary> Decodes a URL-encoded string.
360                 /// 
361                 /// <p>Any occurences of %HH are decoded to the hex value represented.
362                 /// However, this method does NOT decode "+" into " ".
363                 /// 
364                 /// </summary>
365                 /// <param name="URLEncoded">    String to decode.
366                 /// 
367                 /// </param>
368                 /// <returns> The decoded string.
369                 /// 
370                 /// </returns>
371                 /// <exception cref=""> MalformedURLException The URL could not be parsed.
372                 /// </exception>
373                 public static System.String decode(System.String URLEncoded)
374                 {
375                         
376                         
377                         int searchStart = 0;
378                         int fieldStart;
379                         
380                         fieldStart = URLEncoded.IndexOf("%", searchStart);
381                         // Return now if no encoded data
382                         if (fieldStart < 0)
383                         {
384                                 return URLEncoded;
385                         }
386                         
387                         // Decode the %HH value and copy to new string buffer
388                         int fieldEnd = 0; // end of previous field
389                         int dataLen = URLEncoded.Length;
390                         
391                         System.Text.StringBuilder decoded = new System.Text.StringBuilder(dataLen);
392                         
393                         while (true)
394                         {
395                                 if (fieldStart > (dataLen - 3))
396                                 {
397                                         throw new System.UriFormatException("LdapUrl.decode: must be two hex characters following escape character '%'");
398                                 }
399                                 if (fieldStart < 0)
400                                         fieldStart = dataLen;
401                                 // Copy to string buffer from end of last field to start of next
402                                 decoded.Append(URLEncoded.Substring(fieldEnd, (fieldStart) - (fieldEnd)));
403                                 fieldStart += 1;
404                                 if (fieldStart >= dataLen)
405                                         break;
406                                 fieldEnd = fieldStart + 2;
407                                 try
408                                 {
409                                         decoded.Append((char) System.Convert.ToInt32(URLEncoded.Substring(fieldStart, (fieldEnd) - (fieldStart)), 16));
410                                 }
411                                 catch (System.FormatException ex)
412                                 {
413                                         throw new System.UriFormatException("LdapUrl.decode: error converting hex characters to integer \"" + ex.Message + "\"");
414                                 }
415                                 searchStart = fieldEnd;
416                                 if (searchStart == dataLen)
417                                         break;
418                                 fieldStart = URLEncoded.IndexOf("%", searchStart);
419                         }
420                         
421                         return (decoded.ToString());
422                 }
423                 
424                 /// <summary> Encodes an arbitrary string using the URL encoding rules.
425                 /// 
426                 /// <p> Any illegal characters are encoded as %HH. </p>
427                 /// 
428                 /// </summary>
429                 /// <param name="toEncode">    The string to encode.
430                 /// 
431                 /// </param>
432                 /// <returns> The URL-encoded string.
433                 /// 
434                 /// Comment: An illegal character consists of any non graphical US-ASCII character, Unsafe, or reserved characters.
435                 /// </returns>
436                 public static System.String encode(System.String toEncode)
437                 {
438                         System.Text.StringBuilder buffer = new System.Text.StringBuilder(toEncode.Length); //empty but initial capicity of 'length'
439                         System.String temp;
440                         char currChar;
441                         for (int i = 0; i < toEncode.Length; i++)
442                         {
443                                 currChar = toEncode[i];
444                                 if ((((int) currChar <= 0x1F) || ((int) currChar == 0x7F) || (((int) currChar >= 0x80) && ((int) currChar <= 0xFF))) || ((currChar == '<') || (currChar == '>') || (currChar == '\"') || (currChar == '#') || (currChar == '%') || (currChar == '{') || (currChar == '}') || (currChar == '|') || (currChar == '\\') || (currChar == '^') || (currChar == '~') || (currChar == '[') || (currChar == '\'')) || ((currChar == ';') || (currChar == '/') || (currChar == '?') || (currChar == ':') || (currChar == '@') || (currChar == '=') || (currChar == '&')))
445                                 {
446                                         temp = System.Convert.ToString(currChar, 16);
447                                         if (temp.Length == 1)
448                                                 buffer.Append("%0" + temp);
449                                         //if(temp.length()==2) this can only be two or one digit long.
450                                         else
451                                                 buffer.Append("%" + System.Convert.ToString(currChar, 16));
452                                 }
453                                 else
454                                         buffer.Append(currChar);
455                         }
456                         return buffer.ToString();
457                 }
458                 
459                 /// <summary> Returns the base distinguished name encapsulated in the URL.
460                 /// 
461                 /// </summary>
462                 /// <returns> The base distinguished name specified in the URL, or null if none.
463                 /// </returns>
464                 public virtual System.String getDN()
465                 {
466                         return dn;
467                 }
468                 
469                 /// <summary> Sets the base distinguished name encapsulated in the URL.</summary>
470                 /* package */
471                 internal virtual void  setDN(System.String dn)
472                 {
473                         this.dn = dn;
474                         return ;
475                 }
476                 
477                 /// <summary> Returns a valid string representation of this Ldap URL.
478                 /// 
479                 /// </summary>
480                 /// <returns> The string representation of the Ldap URL.
481                 /// </returns>
482                 public override System.String ToString()
483                 {
484                         System.Text.StringBuilder url = new System.Text.StringBuilder(256);
485                         // Scheme
486                         if (secure)
487                         {
488                                 url.Append("ldaps://");
489                         }
490                         else
491                         {
492                                 url.Append("ldap://");
493                         }
494                         // Host:port/dn
495                         if (ipV6)
496                         {
497                                 url.Append("[" + host + "]");
498                         }
499                         else
500                         {
501                                 url.Append(host);
502                         }
503                         
504                         // Port not specified
505                         if (port != 0)
506                         {
507                                 url.Append(":" + port);
508                         }
509                         
510                         if (((System.Object) dn == null) && (attrs == null) && (scope == DEFAULT_SCOPE) && ((System.Object) filter == null) && (extensions == null))
511                         {
512                                 return url.ToString();
513                         }
514                         
515                         url.Append("/");
516                         
517                         if ((System.Object) dn != null)
518                         {
519                                 url.Append(dn);
520                         }
521                         
522                         if ((attrs == null) && (scope == DEFAULT_SCOPE) && ((System.Object) filter == null) && (extensions == null))
523                         {
524                                 return url.ToString();
525                         }
526                         
527                         // attributes
528                         url.Append("?");
529                         if (attrs != null)
530                         {
531                                 //should we check also for attrs != "*"
532                                 for (int i = 0; i < attrs.Length; i++)
533                                 {
534                                         url.Append(attrs[i]);
535                                         if (i < (attrs.Length - 1))
536                                         {
537                                                 url.Append(",");
538                                         }
539                                 }
540                         }
541                         
542                         if ((scope == DEFAULT_SCOPE) && ((System.Object) filter == null) && (extensions == null))
543                         {
544                                 return url.ToString();
545                         }
546                         
547                         // scope
548                         url.Append("?");
549                         if (scope != DEFAULT_SCOPE)
550                         {
551                                 if (scope == LdapConnection.SCOPE_ONE)
552                                 {
553                                         url.Append("one");
554                                 }
555                                 else
556                                 {
557                                         url.Append("sub");
558                                 }
559                         }
560                         
561                         if (((System.Object) filter == null) && (extensions == null))
562                         {
563                                 return url.ToString();
564                         }
565                         
566                         // filter
567                         if ((System.Object) filter == null)
568                         {
569                                 url.Append("?");
570                         }
571                         else
572                         {
573                                 url.Append("?" + Filter);
574                         }
575                         
576                         if (extensions == null)
577                         {
578                                 return url.ToString();
579                         }
580                         
581                         // extensions
582                         url.Append("?");
583                         if (extensions != null)
584                         {
585                                 for (int i = 0; i < extensions.Length; i++)
586                                 {
587                                         url.Append(extensions[i]);
588                                         if (i < (extensions.Length - 1))
589                                         {
590                                                 url.Append(",");
591                                         }
592                                 }
593                         }
594                         return url.ToString();
595                 }
596                 
597                 private System.String[] parseList(System.String listStr, char delimiter, int listStart, int listEnd)
598                 // end of list + 1
599                 {
600                         System.String[] list;
601                         // Check for and empty string
602                         if ((listEnd - listStart) < 1)
603                         {
604                                 return null;
605                         }
606                         // First count how many items are specified
607                         int itemStart = listStart;
608                         int itemEnd;
609                         int itemCount = 0;
610                         while (itemStart > 0)
611                         {
612                                 // itemStart == 0 if no delimiter found
613                                 itemCount += 1;
614                                 itemEnd = listStr.IndexOf((System.Char) delimiter, itemStart);
615                                 if ((itemEnd > 0) && (itemEnd < listEnd))
616                                 {
617                                         itemStart = itemEnd + 1;
618                                 }
619                                 else
620                                 {
621                                         break;
622                                 }
623                         }
624                         // Now fill in the array with the attributes
625                         itemStart = listStart;
626                         list = new System.String[itemCount];
627                         itemCount = 0;
628                         while (itemStart > 0)
629                         {
630                                 itemEnd = listStr.IndexOf((System.Char) delimiter, itemStart);
631                                 if (itemStart <= listEnd)
632                                 {
633                                         if (itemEnd < 0)
634                                                 itemEnd = listEnd;
635                                         if (itemEnd > listEnd)
636                                                 itemEnd = listEnd;
637                                         list[itemCount] = listStr.Substring(itemStart, (itemEnd) - (itemStart));
638                                         itemStart = itemEnd + 1;
639                                         itemCount += 1;
640                                 }
641                                 else
642                                 {
643                                         break;
644                                 }
645                         }
646                         return list;
647                 }
648                 
649                 
650                 private void  parseURL(System.String url)
651                 {
652                         int scanStart = 0;
653                         int scanEnd = url.Length;
654                         
655                         if ((System.Object) url == null)
656                                 throw new System.UriFormatException("LdapUrl: URL cannot be null");
657                         
658                         // Check if URL is enclosed by < & >
659                         if (url[scanStart] == '<')
660                         {
661                                 if (url[scanEnd - 1] != '>')
662                                         throw new System.UriFormatException("LdapUrl: URL bad enclosure");
663                                 scanStart += 1;
664                                 scanEnd -= 1;
665                         }
666                         
667                         // Determine the URL scheme and set appropriate default port
668                         if (url.Substring(scanStart, (scanStart + 4) - (scanStart)).ToUpper().Equals("URL:".ToUpper()))
669                         {
670                                 scanStart += 4;
671                         }
672                         if (url.Substring(scanStart, (scanStart + 7) - (scanStart)).ToUpper().Equals("ldap://".ToUpper()))
673                         {
674                                 scanStart += 7;
675                                 port = LdapConnection.DEFAULT_PORT;
676                         }
677                         else if (url.Substring(scanStart, (scanStart + 8) - (scanStart)).ToUpper().Equals("ldaps://".ToUpper()))
678                         {
679                                 secure = true;
680                                 scanStart += 8;
681                                 port = LdapConnection.DEFAULT_SSL_PORT;
682                         }
683                         else
684                         {
685                                 throw new System.UriFormatException("LdapUrl: URL scheme is not ldap");
686                         }
687                         
688                         // Find where host:port ends and dn begins
689                         int dnStart = url.IndexOf("/", scanStart);
690                         int hostPortEnd = scanEnd;
691                         bool novell = false;
692                         if (dnStart < 0)
693                         {
694                                 /*
695                                 * Kludge. check for ldap://111.222.333.444:389??cn=abc,o=company
696                                 *
697                                 * Check for broken Novell referral format.  The dn is in
698                                 * the scope position, but the required slash is missing.
699                                 * This is illegal syntax but we need to account for it.
700                                 * Fortunately it can't be confused with anything real.
701                                 */
702                                 dnStart = url.IndexOf("?", scanStart);
703                                 if (dnStart > 0)
704                                 {
705                                         if (url[dnStart + 1] == '?')
706                                         {
707                                                 hostPortEnd = dnStart;
708                                                 dnStart += 1;
709                                                 novell = true;
710                                         }
711                                         else
712                                         {
713                                                 dnStart = - 1;
714                                         }
715                                 }
716                         }
717                         else
718                         {
719                                 hostPortEnd = dnStart;
720                         }
721                         // Check for IPV6 "[ipaddress]:port"
722                         int portStart;
723                         int hostEnd = hostPortEnd;
724                         if (url[scanStart] == '[')
725                         {
726                                 hostEnd = url.IndexOf((System.Char) ']', scanStart + 1);
727                                 if ((hostEnd >= hostPortEnd) || (hostEnd == - 1))
728                                 {
729                                         throw new System.UriFormatException("LdapUrl: \"]\" is missing on IPV6 host name");
730                                 }
731                                 // Get host w/o the [ & ]
732                                 host = url.Substring(scanStart + 1, (hostEnd) - (scanStart + 1));
733                                 portStart = url.IndexOf(":", hostEnd);
734                                 if ((portStart < hostPortEnd) && (portStart != - 1))
735                                 {
736                                         // port is specified
737                                         port = System.Int32.Parse(url.Substring(portStart + 1, (hostPortEnd) - (portStart + 1)));
738                                 }
739                                 else
740                                 {
741                                 }
742                         }
743                         else
744                         {
745                                 portStart = url.IndexOf(":", scanStart);
746                                 // Isolate the host and port
747                                 if ((portStart < 0) || (portStart > hostPortEnd))
748                                 {
749                                         // no port is specified, we keep the default
750                                         host = url.Substring(scanStart, (hostPortEnd) - (scanStart));
751                                 }
752                                 else
753                                 {
754                                         // port specified in URL
755                                         host = url.Substring(scanStart, (portStart) - (scanStart));
756                                         port = System.Int32.Parse(url.Substring(portStart + 1, (hostPortEnd) - (portStart + 1)));
757                                 }
758                         }
759                         
760                         scanStart = hostPortEnd + 1;
761                         if ((scanStart >= scanEnd) || (dnStart < 0))
762                                 return ;
763                         
764                         // Parse out the base dn
765                         scanStart = dnStart + 1;
766                         
767                         int attrsStart = url.IndexOf((System.Char) '?', scanStart);
768                         if (attrsStart < 0)
769                         {
770                                 dn = url.Substring(scanStart, (scanEnd) - (scanStart));
771                         }
772                         else
773                         {
774                                 dn = url.Substring(scanStart, (attrsStart) - (scanStart));
775                         }
776                         
777                         scanStart = attrsStart + 1;
778                         // Wierd novell syntax can have nothing beyond the dn
779                         if ((scanStart >= scanEnd) || (attrsStart < 0) || novell)
780                                 return ;
781                         
782                         // Parse out the attributes
783                         int scopeStart = url.IndexOf((System.Char) '?', scanStart);
784                         if (scopeStart < 0)
785                                 scopeStart = scanEnd - 1;
786                         attrs = parseList(url, ',', attrsStart + 1, scopeStart);
787                         
788                         scanStart = scopeStart + 1;
789                         if (scanStart >= scanEnd)
790                                 return ;
791                         
792                         // Parse out the scope
793                         int filterStart = url.IndexOf((System.Char) '?', scanStart);
794                         System.String scopeStr;
795                         if (filterStart < 0)
796                         {
797                                 scopeStr = url.Substring(scanStart, (scanEnd) - (scanStart));
798                         }
799                         else
800                         {
801                                 scopeStr = url.Substring(scanStart, (filterStart) - (scanStart));
802                         }
803                         if (scopeStr.ToUpper().Equals("".ToUpper()))
804                         {
805                                 scope = LdapConnection.SCOPE_BASE;
806                         }
807                         else if (scopeStr.ToUpper().Equals("base".ToUpper()))
808                         {
809                                 scope = LdapConnection.SCOPE_BASE;
810                         }
811                         else if (scopeStr.ToUpper().Equals("one".ToUpper()))
812                         {
813                                 scope = LdapConnection.SCOPE_ONE;
814                         }
815                         else if (scopeStr.ToUpper().Equals("sub".ToUpper()))
816                         {
817                                 scope = LdapConnection.SCOPE_SUB;
818                         }
819                         else
820                         {
821                                 throw new System.UriFormatException("LdapUrl: URL invalid scope");
822                         }
823                         
824                         
825                         scanStart = filterStart + 1;
826                         if ((scanStart >= scanEnd) || (filterStart < 0))
827                                 return ;
828                         
829                         // Parse out the filter
830                         scanStart = filterStart + 1;
831                         
832                         System.String filterStr;
833                         int extStart = url.IndexOf((System.Char) '?', scanStart);
834                         if (extStart < 0)
835                         {
836                                 filterStr = url.Substring(scanStart, (scanEnd) - (scanStart));
837                         }
838                         else
839                         {
840                                 filterStr = url.Substring(scanStart, (extStart) - (scanStart));
841                         }
842                         
843                         if (!filterStr.Equals(""))
844                         {
845                                 filter = filterStr; // Only modify if not the default filter
846                         }
847                         
848                         
849                         scanStart = extStart + 1;
850                         if ((scanStart >= scanEnd) || (extStart < 0))
851                                 return ;
852                         
853                         // Parse out the extensions
854                         int end = url.IndexOf((System.Char) '?', scanStart);
855                         if (end > 0)
856                                 throw new System.UriFormatException("LdapUrl: URL has too many ? fields");
857                         extensions = parseList(url, ',', scanStart, scanEnd);
858                         
859                         return ;
860                 }
861         }
862 }