// Authors:
// Sunil Kumar (sunilk@novell.com)
// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+// Boris Kirzner (borisk@mainsoft.com)
//
// (C) Novell Inc.
//
using Novell.Directory.Ldap.Utilclass;
using System.Globalization;
using System.DirectoryServices.Design;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.Runtime.InteropServices;
namespace System.DirectoryServices
{
[TypeConverter (typeof (DirectoryEntryConverter))]
public class DirectoryEntry : Component
{
-
+ private static readonly string DEFAULT_LDAP_HOST = "System.DirectoryServices.DefaultLdapHost";
+ private static readonly string DEFAULT_LDAP_PORT = "System.DirectoryServices.DefaultLdapPort";
+
private LdapConnection _conn = null;
private AuthenticationTypes _AuthenticationType=AuthenticationTypes.None;
private DirectoryEntries _Children;
private string _Path="";
private string _Name=null;
private DirectoryEntry _Parent=null;
- private string _Username="";
- private string _Password="";
+ private string _Username;
+ private string _Password;
//private string _Nativeguid;
private PropertyCollection _Properties = null;
private string _SchemaClassName=null;
private bool _Nflag = false;
- private bool _disposed;
+ private bool _usePropertyCache=true;
+ private bool _inPropertiesLoading;
/// <summary>
/// Returns entry's Fully distinguished name.
/// </summary>
internal string Fdn
{
- get {
- if (_Fdn == null) {
- LdapUrl lUrl = new LdapUrl(Path);
+ get {
+ if (_Fdn == null) {
+ LdapUrl lUrl = new LdapUrl (ADsPath);
string fDn=lUrl.getDN();
if(fDn != null)
_Fdn = fDn;
else
- _Fdn="";
+ _Fdn=String.Empty;
}
return _Fdn;
}
{
try {
_conn= new LdapConnection ();
- LdapUrl lUrl=new LdapUrl (Path);
+ LdapUrl lUrl = new LdapUrl (ADsPath);
_conn.Connect(lUrl.Host,lUrl.Port);
- _conn.Bind(Username,Password);
+ _conn.Bind(Username,Password, (Novell.Directory.Ldap.AuthenticationTypes)AuthenticationType);
}
catch(LdapException ex) {
- Console.WriteLine("Error:" + ex.LdapErrorMessage);
throw ex;
}
catch(Exception e) {
- Console.WriteLine("Error:" + e.Message);
throw e;
}
}
/// Initializes the Entry specific properties e.g entry DN etc.
/// </summary>
void InitEntry()
- {
- LdapUrl lUrl=new LdapUrl (Path);
- if(lUrl.getDN()!=null) {
- DN userDn = new DN(lUrl.getDN());
+ {
+ LdapUrl lUrl = new LdapUrl (ADsPath);
+ string dn = lUrl.getDN();
+ if (dn != null ) {
+ if (String.Compare (dn,"rootDSE",true) == 0)
+ InitToRootDse (lUrl.Host,lUrl.Port);
+ else {
+ DN userDn = new DN (dn);
String[] lRdn = userDn.explodeDN(false);
_Name = (string)lRdn[0];
_Parent = new DirectoryEntry(conn);
- LdapUrl cUrl=new LdapUrl(lUrl.Host,lUrl.Port,userDn.Parent.ToString());
- _Parent.Path=cUrl.ToString();
+ _Parent.Path = GetLdapUrlString (lUrl.Host,lUrl.Port,userDn.Parent.ToString ());
+ }
}
else {
_Name=lUrl.Host+":"+lUrl.Port;
{
get
{
- _Children = new DirectoryEntries(Path, conn);
+ _Children = new DirectoryEntries(ADsPath, conn);
return _Children;
}
}
{
get {
if(_Name==null) {
- if(CheckEntry(conn,Path))
+ if(CheckEntry(conn,ADsPath))
InitEntry();
else
- throw new Exception("There is no such object on the server");
+ throw new SystemException("There is no such object on the server");
}
return _Name;
}
{
get {
if(_Parent==null) {
- if(CheckEntry(conn,Path))
+ if(CheckEntry(conn,ADsPath))
InitEntry();
else
- throw new Exception("There is no such object on the server");
+ throw new SystemException("There is no such object on the server");
}
return _Parent;
}
[DefaultValue (true)]
public bool UsePropertyCache
{
- [MonoTODO]
get
{
- throw new NotImplementedException();
+ return _usePropertyCache;
}
- [MonoTODO]
set
{
- throw new NotImplementedException();
+ _usePropertyCache = value;
}
}
return _Path;
}
set {
- _Path = value;
+ if (value == null)
+ _Path = String.Empty;
+ else
+ _Path = value;
}
+ }
+ internal string ADsPath
+ {
+ get {
+ if (Path == null || Path == String.Empty) {
+ DirectoryEntry rootDse = new DirectoryEntry ();
+ rootDse.InitToRootDse (null,-1);
+ string namingContext = (string) rootDse.Properties ["defaultNamingContext"].Value;
+ if ( namingContext == null )
+ namingContext = (string) rootDse.Properties ["namingContexts"].Value;
+
+ LdapUrl actualUrl= new LdapUrl (DefaultHost,DefaultPort,namingContext);
+ return actualUrl.ToString ();
+ }
+ return Path;
+ }
}
/// <summary>
public PropertyCollection Properties
{
get {
- if ( _Properties == null ) {
-
- _Properties = new PropertyCollection();
-
- try {
- LdapSearchResults lsc=conn.Search( Fdn,
- LdapConnection.SCOPE_BASE,
- "objectClass=*",
- null,
- false);
- while(lsc.hasMore()) {
-
- LdapEntry nextEntry = null;
- try {
- nextEntry = lsc.next();
- }
- catch(LdapException e) {
- Console.WriteLine("Error: " + e.LdapErrorMessage);
- // Exception is thrown, go for next entry
- throw e;
- }
- LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
- System.Collections.IEnumerator ienum=attributeSet.GetEnumerator();
- if(ienum!=null) {
- while(ienum.MoveNext()) {
- LdapAttribute attribute=(LdapAttribute)ienum.Current;
- string attributeName = attribute.Name;
- _Properties[attributeName].AddRange(attribute.StringValueArray);
- _Properties[attributeName].Mbit=false;
- // string attributeVal = attribute.StringValue;
- // _Properties[attributeName].Add(attributeVal);
- }
- }
- break;
- }
- }
- catch( LdapException le) {
- if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
- { }
- }
-
- }
- return _Properties;
+ return GetProperties (true);
}
}
}
}
+ private string DefaultHost
+ {
+ get {
+ string defaultHost = (string) AppDomain.CurrentDomain.GetData (DEFAULT_LDAP_HOST);
+
+ if (defaultHost == null) {
+ NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("mainsoft.directoryservices/settings");
+ if (config != null)
+ defaultHost = config ["servername"];
+
+ if (defaultHost == null)
+ defaultHost = "localhost";
+
+ AppDomain.CurrentDomain.SetData (DEFAULT_LDAP_HOST,defaultHost);
+ }
+ return defaultHost;
+ }
+ }
+
+ private int DefaultPort
+ {
+ get {
+ string defaultPortStr = (string) AppDomain.CurrentDomain.GetData (DEFAULT_LDAP_PORT);
+
+ if (defaultPortStr == null) {
+ NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("mainsoft.directoryservices/settings");
+ if (config != null)
+ defaultPortStr = config ["port"];
+
+ if (defaultPortStr == null)
+ defaultPortStr = "389";
+
+ AppDomain.CurrentDomain.SetData (DEFAULT_LDAP_PORT,defaultPortStr);
+ }
+ return Int32.Parse (defaultPortStr);
+ }
+ }
+
+ private void InitToRootDse(string host,int port)
+ {
+ if ( host == null )
+ host = DefaultHost;
+ if ( port < 0 )
+ port = DefaultPort;
+
+ LdapUrl rootPath = new LdapUrl (host,port,String.Empty);
+ string [] attrs = new string [] {"+","*"};
+ DirectoryEntry rootEntry = new DirectoryEntry (rootPath.ToString (),this.Username,this.Password,this.AuthenticationType);
+ DirectorySearcher searcher = new DirectorySearcher (rootEntry,null,attrs,SearchScope.Base);
+
+ SearchResult result = searcher.FindOne ();
+ // copy properties from search result
+ PropertyCollection pcoll = new PropertyCollection ();
+ foreach (string propertyName in result.Properties.PropertyNames) {
+ System.Collections.IEnumerator enumerator = result.Properties [propertyName].GetEnumerator ();
+ if (enumerator != null)
+ while (enumerator.MoveNext ())
+ if (String.Compare (propertyName,"ADsPath",true) != 0)
+ pcoll [propertyName].Add (enumerator.Current);
+ }
+ this.SetProperties (pcoll);
+ this._Name = "rootDSE";
+ }
+
+ private void SetProperties(PropertyCollection pcoll)
+ {
+ _Properties = pcoll;
+ }
+
+ /// <summary>
+ /// Returns entry properties.
+ /// </summary>
+ /// <param name="forceLoad">Specifies whenever to force the properties load from the server if local property cache is empty.</param>
+ /// <returns></returns>
+ private PropertyCollection GetProperties(bool forceLoad)
+ {
+ if (_Properties == null) {
+ // load properties into a different collection
+ // to preserve original collection state if exception occurs
+ PropertyCollection properties = new PropertyCollection (this);
+ if (forceLoad && !Nflag)
+ LoadProperties (properties,null);
+
+ _Properties = properties ;
+ }
+ return _Properties;
+ }
+
+ /// <summary>
+ /// Loads the values of the specified properties into the property cache.
+ /// </summary>
+ /// <param name="propertyNames">An array of the specified properties.</param>
+ private void LoadProperties(PropertyCollection properties,string[] propertyNames)
+ {
+ _inPropertiesLoading = true;
+ try {
+ LdapSearchResults lsc=conn.Search (Fdn,LdapConnection.SCOPE_BASE,"objectClass=*",propertyNames,false);
+ if (lsc.hasMore ()) {
+ LdapEntry nextEntry = lsc.next ();
+ string [] lowcasePropertyNames = null;
+ int length = 0;
+ if (propertyNames != null) {
+ length = propertyNames.Length;
+ lowcasePropertyNames = new string [length];
+ for(int i=0; i < length; i++)
+ lowcasePropertyNames [i] = propertyNames [i].ToLower ();
+ }
+ foreach (LdapAttribute attribute in nextEntry.getAttributeSet ()) {
+ string attributeName = attribute.Name;
+ if ((propertyNames == null) || (Array.IndexOf (lowcasePropertyNames,attributeName.ToLower ()) != -1)) {
+ properties [attributeName].Value = null;
+ properties [attributeName].AddRange (attribute.StringValueArray);
+ properties [attributeName].Mbit=false;
+ }
+ }
+ }
+ }
+ finally {
+ _inPropertiesLoading = false;
+ }
+ }
+
/// <summary>
/// Searches an entry in the Ldap directory and returns the attribute value
/// </summary>
nextEntry = lsc.next();
}
catch(LdapException e) {
- Console.WriteLine("Error: " + e.LdapErrorMessage);
// Exception is thrown, go for next entry
throw e;
}
string eDn=lUrl.getDN();
if(eDn==null)
{
- eDn="";
+ eDn = String.Empty;
}
+ // rootDSE is a "virtual" entry that always exists
+ else if (String.Compare (eDn,"rootDSE",true) == 0)
+ return true;
+
string[] attrs={"objectClass"};
try
{
}
catch(LdapException e)
{
- Console.WriteLine("Error: " + e.LdapErrorMessage);
// Exception is thrown, go for next entry
throw e;
}
/// </remarks>
public void Close()
{
- conn.Disconnect();
+ if (_conn != null && _conn.Connected) {
+ _conn.Disconnect();
+ }
}
/// <summary>
/// </param>
public void MoveTo(DirectoryEntry newParent)
{
+ string oldParentFdn = Parent.Fdn;
conn.Rename(Fdn, Name, newParent.Fdn, true);
+ // TBD : threat multiple name instance in path
+ Path = Path.Replace(oldParentFdn,newParent.Fdn);
+ RefreshEntry();
}
/// <summary>
public void MoveTo( DirectoryEntry newParent,
string newName )
{
+ string oldParentFdn = Parent.Fdn;
conn.Rename(Fdn, newName, newParent.Fdn, true);
+ // TBD : threat multiple name instance in path
+ Path = Path.Replace(oldParentFdn,newParent.Fdn).Replace(Name,newName);
+ RefreshEntry();
}
/// <summary>
/// </remarks>
public void Rename( string newName )
{
+ string oldName = Name;
conn.Rename( Fdn, newName, true);
+ // TBD : threat multiple name instance in path
+ Path = Path.Replace(oldName,newName);
+ RefreshEntry();
}
/// <summary>
throw new NotImplementedException();
}
+#if NET_2_0
+ /// <summary>
+ /// Gets a property value from the native Active Directory Entry.
+ /// </summary>
+ /// <param name="propertyName">The name of the property to get.
+ /// </param>
+ /// <returns>The value of the property</returns>
+ /// <remarks>
+ /// Not implemented yet.
+ [ComVisibleAttribute (false)]
+ [MonoNotSupported ("")]
+ public object InvokeGet (string propertyName)
+ {
+ throw new NotImplementedException ();
+ }
+
+ /// <summary>
+ /// Sets a property value on the native Active Directory Entry.
+ /// </summary>
+ /// <param name="propertyName">The name of the property to get.
+ /// </param>
+ /// <param name="args">
+ /// An array of type Object that contains the arguments of the property
+ /// beeing set.
+ /// </param>
+ /// <remarks>
+ /// Not implemented yet.
+ [ComVisibleAttribute (false)]
+ [MonoNotSupported ("")]
+ public void InvokeSet (string propertyName, params object [] args)
+ {
+ throw new NotImplementedException ();
+ }
+#endif
+
/// <summary>
/// Creates a copy of this entry, as a child of the specified parent, with
/// the specified new name.
/// </remarks>
public void CommitChanges()
{
+ if(UsePropertyCache)
+ {
+ CommitEntry();
+ }
+ }
+
+ private void CommitEntry()
+ {
+ PropertyCollection properties = GetProperties(false);
if(!Nflag)
{
System.Collections.ArrayList modList = new System.Collections.ArrayList();
- System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
- while(id.MoveNext())
+ foreach (string attribute in properties.PropertyNames)
{
- string attribute=(string)id.Key;
LdapAttribute attr=null;
- if(Properties[attribute].Mbit)
+ if (properties [attribute].Mbit)
{
- if(Properties[attribute].Count==1)
- {
- String val = (String)Properties[attribute].Value;
- attr = new LdapAttribute( attribute , val);
- }
- else
- {
- Object[] vals=(Object [])Properties[attribute].Value;
- String[] aStrVals= new String[Properties[attribute].Count];
- Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
- attr = new LdapAttribute( attribute , aStrVals);
+ switch (properties [attribute].Count) {
+ case 0:
+ attr = new LdapAttribute (attribute, new string [0]);
+ modList.Add (new LdapModification (LdapModification.DELETE, attr));
+ break;
+ case 1:
+ string val = (string) properties [attribute].Value;
+ attr = new LdapAttribute (attribute, val);
+ modList.Add (new LdapModification (LdapModification.REPLACE, attr));
+ break;
+ default:
+ object [] vals = (object [])properties [attribute].Value;
+ string [] aStrVals = new string [properties [attribute].Count];
+ Array.Copy (vals, 0, aStrVals, 0, properties [attribute].Count);
+ attr = new LdapAttribute (attribute, aStrVals);
+ modList.Add (new LdapModification (LdapModification.REPLACE, attr));
+ break;
}
- modList.Add( new LdapModification(LdapModification.REPLACE, attr));
- Properties[attribute].Mbit=false;
+ properties [attribute].Mbit=false;
}
-// Console.WriteLine(attribute + "Total no of attr value" + Properties[attribute].Count);
}
- LdapModification[] mods = new LdapModification[modList.Count];
- Type mtype=Type.GetType("System.DirectoryServices.LdapModification");
- mods = (LdapModification[])modList.ToArray(typeof(LdapModification));
- ModEntry(mods);
+ if (modList.Count > 0) {
+ LdapModification[] mods = new LdapModification[modList.Count];
+ Type mtype = typeof (LdapModification);
+ mods = (LdapModification[])modList.ToArray(mtype);
+ ModEntry(mods);
+ }
}
else
{
LdapAttributeSet attributeSet = new LdapAttributeSet();
- System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
- while(id.MoveNext())
+ foreach (string attribute in properties.PropertyNames)
{
- string attribute=(string)id.Key;
-// Console.WriteLine("attribute:" + attribute + "Vals:" + Properties[attribute][0]);
- if(Properties[attribute].Count==1)
+ if (properties [attribute].Count == 1)
{
- String val = (String)Properties[attribute].Value;
+ string val = (string) properties [attribute].Value;
attributeSet.Add(new LdapAttribute(attribute, val));
}
else
{
- Object[] vals=(Object [])Properties[attribute].Value;
- String[] aStrVals= new String[Properties[attribute].Count];
- Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
+ object[] vals = (object []) properties [attribute].Value;
+ string[] aStrVals = new string [properties [attribute].Count];
+ Array.Copy (vals,0,aStrVals,0,properties [attribute].Count);
attributeSet.Add( new LdapAttribute( attribute , aStrVals));
}
}
LdapEntry newEntry = new LdapEntry( Fdn, attributeSet );
- conn.Add( newEntry );
+ conn.Add( newEntry );
+ Nflag = false;
}
}
- [MonoTODO]
+ internal void CommitDeferred()
+ {
+ if (!_inPropertiesLoading && !UsePropertyCache && !Nflag)
+ {
+ CommitEntry();
+ }
+ }
+
+ void RefreshEntry()
+ {
+ _Properties = null;
+ _Fdn = null;
+ _Name = null;
+ _Parent = null;
+ _SchemaClassName = null;
+ InitEntry();
+ }
+
+ /// <summary>
+ /// Loads the values of the specified properties into the property cache.
+ /// </summary>
public void RefreshCache ()
{
- throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache()");
+ // note that GetProperties must be called with false, elswere infinite loop will be caused
+ PropertyCollection properties = new PropertyCollection ();
+ LoadProperties(properties, null);
+ SetProperties (properties);
}
- [MonoTODO]
- public void RefreshCache (string[] args)
+ /// <summary>
+ /// Loads the values of the specified properties into the property cache.
+ /// </summary>
+ /// <param name="propertyNames">An array of the specified properties. </param>
+ public void RefreshCache (string[] propertyNames)
{
- throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache(System.String[])");
+ // note that GetProperties must be called with false, elswere infinite loop will be caused
+ LoadProperties(GetProperties(false),propertyNames);
}
protected override void Dispose (bool disposing)
{
- if (!_disposed && disposing) {
+ if (disposing) {
Close ();
- _disposed = true;
}
base.Dispose (disposing);
}
+
+ internal static string GetLdapUrlString(string host, int port, string dn)
+ {
+ LdapUrl lUrl;
+ if (port == LdapConnection.DEFAULT_PORT)
+ lUrl = new LdapUrl (host,0,dn);
+ else
+ lUrl = new LdapUrl (host,port,dn);
+ return lUrl.ToString();
+ }
}
}