/******************************************************************************
* The MIT License
* Copyright (c) 2003 Novell Inc. www.novell.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/
//
// Novell.Directory.Ldap.LdapDN.cs
//
// Author:
// Sunil Kumar (Sunilk@novell.com)
//
// (C) 2003 Novell, Inc (http://www.novell.com)
//
using System;
using Novell.Directory.Ldap.Utilclass;
namespace Novell.Directory.Ldap
{
/// A utility class to facilitate composition and deomposition
/// of distinguished names DNs.
///
/// Specifies methods for manipulating a distinguished name DN
/// and a relative distinguished name RDN.
///
public class LdapDN
{
/// Compares the two strings per the distinguishedNameMatch equality matching
/// (using case-ignore matching). IllegalArgumentException is thrown if one
/// or both DNs are invalid. UnsupportedOpersationException is thrown if the
/// API implementation is not able to detemine if the DNs match or not.
///
///
/// String form of the first DN to compare.
///
///
/// String form of the second DN to compare.
///
///
/// Returns true if the two strings correspond to the same DN; false
/// if the DNs are different.
///
[CLSCompliantAttribute(false)]
public static bool equals(System.String dn1, System.String dn2)
{
DN dnA = new DN(dn1);
DN dnB = new DN(dn2);
return dnA.Equals(dnB);
}
/// Returns the RDN after escaping the characters requiring escaping.
///
/// For example, for the rdn "cn=Acme, Inc", the escapeRDN method
/// returns "cn=Acme\, Inc".
///
/// escapeRDN escapes the AttributeValue by inserting '\' before the
/// following chars: * ',' '+' '"' '\' 'LESSTHAN' 'GREATERTHAN' ';'
/// '#' if it comes at the beginning of the string, and
/// ' ' (space) if it comes at the beginning or the end of a string.
/// Note that single-valued attributes can be used because of ambiguity. See
/// RFC 2253
///
///
/// The RDN to escape.
///
///
/// The RDN with escaping characters.
///
public static System.String escapeRDN(System.String rdn)
{
System.Text.StringBuilder escapedS = new System.Text.StringBuilder(rdn);
int i = 0;
while (i < escapedS.Length && escapedS[i] != '=')
{
i++; //advance until we find the separator =
}
if (i == escapedS.Length)
{
throw new System.ArgumentException("Could not parse RDN: Attribute " + "type and name must be separated by an equal symbol, '='");
}
i++;
//check for a space or # at the beginning of a string.
if ((escapedS[i] == ' ') || (escapedS[i] == '#'))
{
escapedS.Insert(i++, '\\');
}
//loop from second char to the second to last
for (; i < escapedS.Length; i++)
{
if ((escapedS[i] == ',') || (escapedS[i] == '+') || (escapedS[i] == '"') || (escapedS[i] == '\\') || (escapedS[i] == '<') || (escapedS[i] == '>') || (escapedS[i] == ';'))
{
escapedS.Insert(i++, '\\');
}
}
//check last char for a space
if (escapedS[escapedS.Length - 1] == ' ')
{
escapedS.Insert(escapedS.Length - 1, '\\');
}
return escapedS.ToString();
}
/// Returns the individual components of a distinguished name (DN).
///
///
/// The distinguished name, for example, "cn=Babs
/// Jensen,ou=Accounting,o=Acme,c=US"
///
///
/// If true, returns only the values of the
/// components and not the names. For example, "Babs
/// Jensen", "Accounting", "Acme", "US" instead of
/// "cn=Babs Jensen", "ou=Accounting", "o=Acme", and
/// "c=US".
///
///
/// An array of strings representing the individual components
/// of a DN, or null if the DN is not valid.
///
public static System.String[] explodeDN(System.String dn, bool noTypes)
{
DN dnToExplode = new DN(dn);
return dnToExplode.explodeDN(noTypes);
}
/// Returns the individual components of a relative distinguished name
/// (RDN), normalized.
///
///
/// The relative distinguished name, or in other words,
/// the left-most component of a distinguished name.
///
///
/// If true, returns only the values of the
/// components, and not the names of the component, for
/// example "Babs Jensen" instead of "cn=Babs Jensen".
///
///
/// An array of strings representing the individual components
/// of an RDN, or null if the RDN is not a valid RDN.
///
public static System.String[] explodeRDN(System.String rdn, bool noTypes)
{
RDN rdnToExplode = new RDN(rdn);
return rdnToExplode.explodeRDN(noTypes);
}
/// Returns true if the string conforms to distinguished name syntax.
/// String to evaluate fo distinguished name syntax.
///
/// true if the dn is valid.
///
public static bool isValid(System.String dn)
{
try
{
new DN(dn);
}
catch (System.ArgumentException iae)
{
return false;
}
return true;
}
/// Returns the DN normalized by removal of non-significant space characters
/// as per RFC 2253, section4.
///
///
/// a normalized string
///
public static System.String normalize(System.String dn)
{
DN testDN = new DN(dn);
return testDN.ToString();
}
/// Returns the RDN after unescaping the characters requiring escaping.
///
/// For example, for the rdn "cn=Acme\, Inc", the unescapeRDN method
/// returns "cn=Acme, Inc".
/// unescapeRDN unescapes the AttributeValue by
/// removing the '\' when the next character fits the following:
/// ',' '+' '"' '\' 'LESSTHAN' 'GREATERTHAN' ';'
/// '#' if it comes at the beginning of the Attribute Name
/// (without the '\').
/// ' ' (space) if it comes at the beginning or the end of the Attribute Name
///
///
/// The RDN to unescape.
///
///
/// The RDN with the escaping characters removed.
///
public static System.String unescapeRDN(System.String rdn)
{
System.Text.StringBuilder unescaped = new System.Text.StringBuilder();
int i = 0;
while (i < rdn.Length && rdn[i] != '=')
{
i++; //advance until we find the separator =
}
if (i == rdn.Length)
{
throw new System.ArgumentException("Could not parse rdn: Attribute " + "type and name must be separated by an equal symbol, '='");
}
i++;
//check if the first two chars are "\ " (slash space) or "\#"
if ((rdn[i] == '\\') && (i + 1 < rdn.Length - 1) && ((rdn[i + 1] == ' ') || (rdn[i + 1] == '#')))
{
i++;
}
for (; i < rdn.Length; i++)
{
//if the current char is a slash, not the end char, and is followed
// by a special char then...
if ((rdn[i] == '\\') && (i != rdn.Length - 1))
{
if ((rdn[i + 1] == ',') || (rdn[i + 1] == '+') || (rdn[i + 1] == '"') || (rdn[i + 1] == '\\') || (rdn[i + 1] == '<') || (rdn[i + 1] == '>') || (rdn[i + 1] == ';'))
{
//I'm not sure if I have to check for these special chars
continue;
}
//check if the last two chars are "\ "
else if ((rdn[i + 1] == ' ') && (i + 2 == rdn.Length))
{
//if the last char is a space
continue;
}
}
unescaped.Append(rdn[i]);
}
return unescaped.ToString();
}
} //end class LdapDN
}