23ccd6b7d8f8ca4d14b76081266224a633f38d00
[mono.git] / mcs / class / System.DirectoryServices / System.DirectoryServices / DirectoryEntry.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 //
25 // System.DirectoryServices.DirectoryEntry.cs
26 //
27 // Authors:
28 //   Sunil Kumar (sunilk@novell.com)
29 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
30 //
31 // (C)  Novell Inc.
32 //
33
34 using System.ComponentModel;
35 using Novell.Directory.Ldap;
36 using Novell.Directory.Ldap.Utilclass;
37 using System.Globalization;
38 using System.DirectoryServices.Design;
39
40 namespace System.DirectoryServices
41 {
42         
43         /// <summary>
44         ///Encapsulates a node or object in the Ldap Directory hierarchy.
45         /// </summary>
46         [TypeConverter (typeof (DirectoryEntryConverter))]
47         public class DirectoryEntry : Component 
48         {
49                 
50                 private LdapConnection _conn = null;
51                 private AuthenticationTypes _AuthenticationType=AuthenticationTypes.None;
52                 private DirectoryEntries _Children;
53                 private string _Fdn = null;
54                 private string _Path="";
55                 private string _Name=null;
56                 private DirectoryEntry _Parent=null;
57                 private string _Username;
58                 private string _Password;
59                 //private string _Nativeguid;
60                 private PropertyCollection _Properties = null;
61                 private string _SchemaClassName=null;
62                 private bool _Nflag = false;
63                 private bool _usePropertyCache=true;
64                 private bool _inPropertiesLoading;
65
66                 /// <summary>
67                 /// Returns entry's Fully distinguished name.
68                 /// </summary>
69                 internal string Fdn
70                 {
71                         get     {
72                                 if (_Fdn == null) {
73                                         LdapUrl lUrl = new LdapUrl(Path);
74                                         string fDn=lUrl.getDN();
75                                         if(fDn != null)
76                                                 _Fdn = fDn;
77                                         else
78                                                 _Fdn="";
79                                 }
80                                 return _Fdn;
81                         }
82                 }
83
84                 /// <summary>
85                 ///  Returns the connection object used to communicate with
86                 /// Ldap server
87                 /// </summary>
88                 internal LdapConnection conn
89                 {
90                         get                     {
91                                 if( _conn == null)
92                                         InitBlock();
93
94                                 return _conn;
95                         }
96                         set                     {
97                                 _conn=value;
98                         }
99                 }
100
101                 /// <summary>
102                 /// Flag to check whether the entry is to be cerated or it already
103                 /// exists.
104                 /// </summary>
105                 internal bool Nflag
106                 {
107                         get                     {
108                                 return _Nflag;
109                         }
110                         set                     {
111                                 _Nflag = value;
112                         }
113                 }
114
115                 /// <summary> Initializes the Connection and other properties.
116                 /// 
117                 /// </summary>
118                 private void InitBlock()
119                 {
120                         try                     {
121                                 _conn= new LdapConnection ();
122                                 LdapUrl lUrl=new LdapUrl (Path);
123                                 _conn.Connect(lUrl.Host,lUrl.Port);
124                                 _conn.Bind(Username,Password);
125                         }
126                         catch(LdapException ex)                 {
127                                 throw ex;
128                         }
129                         catch(Exception e)                      {
130                                 throw e;
131                         }
132                 }
133
134                 /// <summary>
135                 /// Initializes the Entry specific properties e.g entry DN etc.
136                 /// </summary>
137                 void InitEntry()
138                 {
139                         LdapUrl lUrl=new LdapUrl (Path);
140                         if(lUrl.getDN()!=null)                  {
141                                 DN userDn = new DN(lUrl.getDN());
142                                 String[] lRdn = userDn.explodeDN(false);
143                                 _Name = (string)lRdn[0];
144                                 _Parent = new DirectoryEntry(conn);
145                                 LdapUrl cUrl=new LdapUrl(lUrl.Host,lUrl.Port,userDn.Parent.ToString());
146                                 _Parent.Path=cUrl.ToString();
147                         }
148                         else                    {
149                                 _Name=lUrl.Host+":"+lUrl.Port;
150                                 _Parent = new DirectoryEntry(conn);
151                                 _Parent.Path = "Ldap:";
152                         }
153                 }
154
155                 /// <summary>
156                 /// Initializes a new instance of the DirectoryEntry class
157                 /// </summary>
158                 public DirectoryEntry()
159                 {
160                 }
161
162                 /// <summary>
163                 /// Initializes a new instance of the DirectoryEntry class that binds
164                 ///  to the specified native Active Directory object.
165                 /// </summary>
166                 /// <param name="adsObject"> native active directory object</param>
167                 public DirectoryEntry(object adsObject)
168                 {
169                          throw new NotImplementedException();
170                 }
171
172                 /// <summary>
173                 /// Initializes a new instance of the DirectoryEntry class that binds
174                 ///  this instance to the node in Ldap Directory located at the
175                 ///  specified path.
176                 /// </summary>
177                 /// <param name="path"> Path of the entry i.e Ldap URL specifying 
178                 /// entry path</param>
179                 public DirectoryEntry(string path)
180                 {
181                         _Path=path;
182                 }
183
184                 /// <summary>
185                 /// Initializes a new instance of the DirectoryEntry class. The Path,
186                 ///  Username, and Password properties are set to the specified values.
187                 /// </summary>
188                 /// <param name="path">Path of the entry i.e Ldap URL specifying 
189                 /// entry path</param>
190                 /// <param name="username">user name to use when authenticating the client
191                 /// </param>
192                 /// <param name="password">password to use when authenticating the client
193                 /// </param>
194                 public DirectoryEntry(string path,string username,string password)
195                 {
196                         _Path=path;
197                         _Username=username;
198                         _Password=password;
199                 }
200
201                 /// <summary>
202                 /// Initializes a new instance of the DirectoryEntry class. The Path,
203                 ///  Username, and Password properties are set to the specified values.
204                 /// </summary>
205                 /// <param name="path">Path of the entry i.e Ldap URL specifying 
206                 /// entry path</param>
207                 /// <param name="username">user name to use when authenticating the client
208                 /// </param>
209                 /// <param name="password">password to use when authenticating the client
210                 /// </param>
211                 /// <param name="authenticationType"> type of authentication to use</param>
212                 public DirectoryEntry(
213                                 string path,
214                                 string username,
215                                 string password,
216                                 AuthenticationTypes authenticationType)
217                 {
218                         _Path=path;
219                         _Username=username;
220                         _Password=password;
221                         _AuthenticationType=authenticationType;
222                 }
223
224                 /// <summary>
225                 /// Creates the entry object
226                 /// </summary>
227                 /// <param name="lconn">Connection object used to communicate with
228                 /// Ldap server</param>
229                 internal DirectoryEntry(LdapConnection lconn)
230                 {
231                         conn = lconn;
232                 }
233
234                 /// <summary>
235                 /// Returns Type of authentication to use while Binding to Ldap server
236                 /// </summary>
237                 [DSDescription ("Type of authentication to use while Binding to Ldap server")]
238                 [DefaultValue (AuthenticationTypes.None)]
239                 public AuthenticationTypes AuthenticationType 
240                 {
241                         get 
242                         {
243                                 return _AuthenticationType;
244                         }
245                         set 
246                         {
247                                 _AuthenticationType = value;
248                         }
249                 }
250
251                 /// <summary>
252                 /// Gets a DirectoryEntries containing the child entries of this node
253                 ///  in the Ldap Directory hierarchy.
254                 /// </summary>
255                 /// <value>A DirectoryEntries containing the child entries of this node
256                 ///  in the Ldap Directory hierarchy.</value>
257                 ///  <remarks>
258                 ///  The child entries are only the immediate children of this node.
259                 ///  Use this property to find, retrieve, or create a directory entry
260                 ///  in the hierarchy. This property is a collection that, along with 
261                 ///  usual iteration capabilities, provides an Add method through which
262                 ///  you add a node to the collection directly below the parent node
263                 ///  that you are currently bound to. When adding a node to the 
264                 ///  collection, you must specify a name for the new node and the name of 
265                 ///  a schema template that you want to associate with the node. For 
266                 ///  example, you might want to use a schema titled "Computer" to add 
267                 ///  new computers to the hierarchy.
268                 ///  </remarks>
269                 [DSDescription ("Child entries of this node")]
270                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
271                 [Browsable (false)]
272                 public DirectoryEntries Children 
273                 {
274                         get 
275                         {
276                                 _Children = new DirectoryEntries(Path, conn);
277                                 return _Children;
278                         }
279                 }
280
281                 /// <summary>
282                 /// Gets the globally unique identifier (GUID) of the DirectoryEntry
283                 /// </summary>
284                 /// <value>The globally unique identifier of the DirectoryEntry.</value>
285                 /// <remarks>
286                 /// Not implemented yet.                
287                 /// </remarks>
288                 [DSDescription ("A globally unique identifier for this DirectoryEntry")]
289                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
290                 [Browsable (false)]
291                 [MonoTODO]
292                 public Guid Guid 
293                 {
294                         get 
295                         {
296                                 throw new NotImplementedException();
297                         }
298
299                 }
300
301                 /// <summary>
302                 /// Gets the name of the object as named with the underlying directory
303                 ///  service
304                 /// </summary>
305                 /// <value>The name of the object as named with the underlying directory
306                 ///  service</value>
307                 /// <remarks>This name, along with SchemaClassName, distinguishes this
308                 ///  entry from its siblings and must be unique amongst its siblings 
309                 ///  in each instance of DirectoryEntry.</remarks>
310                 [DSDescription ("The name of the object as named with the underlying directory")]
311                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
312                 [Browsable (false)]
313                 public string Name 
314                 {
315                         get                                                             {
316                                 if(_Name==null)                         {
317                                         if(CheckEntry(conn,Path))
318                                                 InitEntry();
319                                         else
320                                                 throw new SystemException("There is no such object on the server");
321                                 }
322                                 return _Name;
323                         }
324                 }
325
326                 /// <summary>
327                 /// Gets this entry's parent in the Ldap Directory hierarchy.
328                 /// </summary>
329                 /// <value>This entry's parent in the Active Directory hierarc</value>
330                 [DSDescription ("This entry's parent in the Ldap Directory hierarchy.")]
331                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
332                 [Browsable (false)]
333                 public DirectoryEntry Parent 
334                 {
335                         get                     {
336                                 if(_Parent==null)                               {
337                                         if(CheckEntry(conn,Path))
338                                                 InitEntry();
339                                         else
340                                                 throw new SystemException("There is no such object on the server");
341                                 }
342                                 return _Parent;
343                         }
344                 }
345
346                 /// <summary>
347                 /// Gets the globally unique identifier of the DirectoryEntry, as 
348                 /// returned from the provider
349                 /// </summary>
350                 /// <value>
351                 /// The globally unique identifier of the DirectoryEntry, as returned 
352                 /// from the provider.
353                 /// </value>
354                 /// <remarks>
355                 /// Not implemented yet.
356                 /// </remarks>
357                 [DSDescription ("The globally unique identifier of the DirectoryEntry, as returned from the provider")]
358                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
359                 [Browsable (false)]
360                 [MonoTODO]
361                 public string NativeGuid 
362                 {
363                         get                     {
364                                 throw new NotImplementedException();
365                         }
366                 }
367
368                 /// <summary>
369                 /// Gets the native Active Directory Service Interfaces (ADSI) object.
370                 /// </summary>
371                 /// <remarks>
372                 /// Not implemented yet
373                 [DSDescription ("The native Active Directory Service Interfaces (ADSI) object.")]
374                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
375                 [Browsable (false)]
376                 public object NativeObject 
377                 {
378                         [MonoTODO]
379                         get                     {
380                                 throw new NotImplementedException();
381                         }
382                 }
383
384                 /// <summary>
385                 /// Determines if a cache should be used.
386                 /// </summary>
387                 [DSDescription ("Determines if a cache should be used.")]
388                 [DefaultValue (true)]
389                 public bool UsePropertyCache
390                 {
391                         get 
392                         {
393                                 return _usePropertyCache;
394                         }
395                         set 
396                         {
397                                 _usePropertyCache = value;
398                         }
399                 }
400
401                 /// <summary>
402                 /// Gets or sets the password to use when authenticating the client.
403                 /// </summary>
404                 /// <value>
405                 /// The password to use when authenticating the client.
406                 /// </value>
407                 /// <remarks>
408                 /// You can set the Username and password in order to specify alternate 
409                 /// credentials with which to access the information in Ldap Directory. 
410                 /// Any other DirectoryEntry objects retrieved from this instance (for 
411                 /// example, through Children) are automatically created with the same 
412                 /// alternate credentials.
413                 /// </remarks>
414                 [DSDescription ("The password to use when authenticating the client.")]
415                 [DefaultValue (null)]
416                 [Browsable (false)]
417                 public string Password 
418                 {
419                         get             {
420                                 return _Password;
421                         }
422                         set                     {
423                                 _Password = value;
424                         }
425
426                 }
427
428                 /// <summary>
429                 /// Gets or sets the user name to use when authenticating the client.
430                 /// </summary>
431                 /// <value>
432                 /// The user name to use when authenticating the client.
433                 /// </value>
434                 /// <remarks>
435                 /// You can set the user name and Password in order to specify alternate 
436                 /// credentials with which to access the information in Ldap Directory. 
437                 /// Any other DirectoryEntry objects retrieved from this instance (for 
438                 /// example, through Children) are automatically created with the same 
439                 /// alternate 
440                 /// </remarks>
441                 [DSDescription ("The user name to use when authenticating the client.")]
442                 [DefaultValue (null)]
443                 [Browsable (false)]
444                 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
445                 public string Username 
446                 {
447                         get                     {
448                                 return _Username ;
449                         }
450                         set                     {
451                                 _Username = value;
452                         }
453
454                 }
455
456                 /// <summary>
457                 /// Gets or sets the path for this DirectoryEntry.
458                 /// </summary>
459                 /// <value>
460                 /// The path of this DirectoryEntry. The default is an empty string ("").
461                 /// </value>
462                 /// <remarks>
463                 /// The Path property uniquely identifies this entry in a networked 
464                 /// environment. This entry can always be retrieved using this Path.
465                 /// 
466                 /// Setting the Path retrieves a new entry from the directory store; it 
467                 /// does not change the path of the currently bound entry.
468                 /// 
469                 /// The classes associated with the DirectoryEntry component can be used 
470                 /// with any of the  Directory service providers. Some of the current 
471                 /// providers are Internet Information Services (IIS), Lightweight Directory 
472                 /// Access Protocol (Ldap), Novell NetWare Directory Service (NDS), and WinNT.
473                 /// 
474                 /// Currently we Support only Ldap provider.
475                 /// e.g Ldap://[hostname]:[port number]/[ObjectFDN]
476                 /// </remarks>
477                 [DSDescription ("The path for this DirectoryEntry.")]
478                 [DefaultValue ("")]
479                 [RecommendedAsConfigurable (true)]
480                 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
481                 public string Path 
482                 {
483                         get                     {
484                                 return _Path;
485                         }
486                         set                     {
487                                 _Path = value;
488                         }
489
490                 }
491
492                 /// <summary>
493                 /// Gets a PropertyCollection of properties set on this object.
494                 /// </summary>
495                 /// <value>
496                 /// A PropertyCollection of properties set on this object.
497                 /// </value>
498                 [DSDescription ("Properties set on this object.")]
499                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
500                 [Browsable (false)]
501                 public PropertyCollection Properties
502                 {
503                         get                     {
504                                 if ( _Properties == null )                              {
505
506                                         _Properties =  new PropertyCollection(this);
507                                         _inPropertiesLoading = true;
508
509                                         try                                     {
510                                                 LdapSearchResults lsc=conn.Search(      Fdn,
511                                                                                                                         LdapConnection.SCOPE_BASE,
512                                                                                                                         "objectClass=*",
513                                                                                                                         null,
514                                                                                                                         false);
515                                                 while(lsc.hasMore())                                            {
516
517                                                         LdapEntry nextEntry = null;
518                                                         try                                                     {
519                                                                 nextEntry = lsc.next();
520                                                         }
521                                                         catch(LdapException e)                                                  {
522                                                                 // Exception is thrown, go for next entry
523                                                                 throw e;
524                                                         }
525                                                         LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
526                                                         System.Collections.IEnumerator ienum=attributeSet.GetEnumerator();
527                                                         if(ienum!=null)                                                 {
528                                                                 while(ienum.MoveNext())                         {
529                                                                         LdapAttribute attribute=(LdapAttribute)ienum.Current;
530                                                                         string attributeName = attribute.Name;
531                                                                         _Properties[attributeName].AddRange(attribute.StringValueArray);
532                                                                         _Properties[attributeName].Mbit=false;
533                                                                         //                                                      string attributeVal = attribute.StringValue;
534                                                                         //                                                      _Properties[attributeName].Add(attributeVal);
535                                                                 }
536                                                         }
537                                                         break;
538                                                 }
539                                         }
540                                         catch( LdapException le)                                        {
541                                                 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
542                                                 {       }
543                                         }
544                                         finally {
545                                                 _inPropertiesLoading = false;
546                                         }
547                                 }
548                                 return _Properties;
549                         }
550                 }
551
552                 /// <summary>
553                 /// Gets the name of the schema used for this DirectoryEntry
554                 /// </summary>
555                 /// <value>
556                 /// The name of the schema used for this DirectoryEntry.
557                 /// </value>
558                 [DSDescription ("The name of the schema used for this DirectoryEntry.")]
559                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
560                 [Browsable (false)]
561                 public string SchemaClassName 
562                 {
563                         get                     {
564                                 if(_SchemaClassName==null)                              {
565                                                 _SchemaClassName = FindAttrValue("structuralObjectClass");
566                                 }
567                                 return _SchemaClassName;
568                         }
569                 }
570
571                 /// <summary>
572                 /// Gets the current schema directory entry.
573                 /// </summary>
574                 /// <remarks>
575                 /// Not implemented yet
576                 [DSDescription ("The current schema directory entry.")]
577                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
578                 [Browsable (false)]
579                 public DirectoryEntry SchemaEntry 
580                 {
581                         [MonoTODO]
582                         get                     {\r
583                                 throw new NotImplementedException();
584                         }
585                 }
586
587                 /// <summary>
588                 /// Searches an entry in the Ldap directory and returns the attribute value
589                 /// </summary>
590                 /// <param name="attrName">attribute whose value is required</param>
591                 /// <returns> value of the attribute stored in Ldap directory</returns>
592                 private string FindAttrValue(string attrName)
593                 {
594                         string aValue=null;
595                         string[] attrs={attrName};
596
597                         LdapSearchResults lsc=conn.Search(      Fdn,
598                                                                                                 LdapConnection.SCOPE_BASE,
599                                                                                                 "objectClass=*",
600                                                                                                 attrs,
601                                                                                                 false);
602                         while(lsc.hasMore())                    {
603                                 LdapEntry nextEntry = null;
604                                 try                                             {
605                                         nextEntry = lsc.next();
606                                 }
607                                 catch(LdapException e)          {
608                                         // Exception is thrown, go for next entry
609                                         throw e;
610                                 }
611                                 LdapAttribute attribute = nextEntry.getAttribute(attrName);
612                                 aValue = attribute.StringValue;
613                                 break;
614                         }
615                         return aValue;
616                 }
617
618                 /// <summary>
619                 /// Modifies an entry in the Ldap directory with the input LdapModification
620                 /// values.
621                 /// </summary>
622                 /// <param name="mods">Array consisting of the entry attribute name and the
623                 /// attribute  values to be modified.</param>
624                 private void ModEntry(LdapModification[] mods)
625                 {
626
627                         try                                             {
628                                 conn.Modify(Fdn,mods);
629                         }
630                         catch(LdapException le) {
631                                 throw le;
632                         }
633                 }
634
635                 /// <summary>
636                 /// Checks whether the entry exists in the Ldap directory or not
637                 /// </summary>
638                 /// <param name="lconn">
639                 /// Connection used to communicate with directory
640                 /// </param>
641                 /// <param name="epath">
642                 /// path of the entry
643                 /// </param>
644                 /// <returns>
645                 ///             true of the entry exists in the Ldap directory
646                 ///             false if entry doesn't exists
647                 /// </returns>
648                 private static bool CheckEntry(LdapConnection lconn, string epath)
649                 {
650                         LdapUrl lUrl=new LdapUrl(epath);
651                         string eDn=lUrl.getDN();
652                         if(eDn==null)
653                         {
654                                 eDn="";
655                         }
656                         string[] attrs={"objectClass"};
657                         try
658                         {
659                                 LdapSearchResults lsc=lconn.Search(     eDn,
660                                         LdapConnection.SCOPE_BASE,
661                                         "objectClass=*",
662                                         attrs,
663                                         false);
664                                 while(lsc.hasMore())
665                                 {
666                                         LdapEntry nextEntry = null;
667                                         try 
668                                         {
669                                                 nextEntry = lsc.next();
670                                         }
671                                         catch(LdapException e) 
672                                         {
673                                                 // Exception is thrown, go for next entry
674                                                 throw e;
675                                         }
676                                         break;
677                                 }
678
679                         }
680                         catch(LdapException le)
681                         {
682                                 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
683                                 {
684                                         return false;
685                                 }
686                                 else
687                                 {
688                                         throw le;
689                                 }
690                         }
691                         catch(Exception e)
692                         {
693                                 throw e;
694                         }
695                         return true;
696                 }
697
698                 /// <summary>
699                 /// Closes the DirectoryEntry and releases any system resources associated 
700                 /// with this component.
701                 /// </summary>
702                 /// <remarks>
703                 /// Following a call to Close, any operations on the DirectoryEntry might 
704                 /// raise exceptions.
705                 /// </remarks>
706                 public void Close()
707                 {
708                         if (conn.Connected) {
709                                 conn.Disconnect();
710                         }
711                 }
712
713                 /// <summary>
714                 /// Creates a copy of this entry as a child of the specified parent.
715                 /// </summary>
716                 /// <param name="newParent">The parent DirectoryEntry.  </param>
717                 /// <returns>A copy of this entry as a child of the specified parent.
718                 [MonoTODO]
719                 public DirectoryEntry CopyTo(DirectoryEntry newParent)
720                 {
721                         throw new NotImplementedException();
722                 }
723
724                 /// <summary>
725                 /// Deletes this entry and its entire subtree from the Active Directory 
726                 /// hierarchy.
727                 /// </summary>
728                 /// <remarks>
729                 /// CAUTION   The entry and its entire subtree are deleted from the 
730                 /// Ldap Directory hierarchy.
731                 /// </remarks>
732                 public void DeleteTree()
733                 {
734                         System.Collections.IEnumerator ienum = Children.GetEnumerator();
735                         while(ienum.MoveNext())
736                         {
737                                 DirectoryEntry de=(DirectoryEntry)ienum.Current;
738                                 conn.Delete(de.Fdn);
739                         }
740                         conn.Delete(Fdn);
741                 }
742
743                 /// <summary>
744                 /// Searches the directory store at the specified path to see whether 
745                 /// an entry exists
746                 /// </summary>
747                 /// <param name="path">
748                 /// The path at which to search the directory store. 
749                 /// </param>
750                 /// <returns>
751                 /// true if an entry exists in the directory store at the specified 
752                 /// path; otherwise, false.
753                 /// </returns>
754                 public static bool Exists(string path)
755                 {
756                         LdapConnection aconn=new LdapConnection();
757                         LdapUrl lurl=new LdapUrl(path);
758                         aconn.Connect(lurl.Host,lurl.Port);
759                         aconn.Bind("","");
760                         if(CheckEntry(aconn,path))
761                                 return true;
762                         else
763                                 return false;
764                 }
765
766                 /// <summary>
767                 /// Moves this entry to the specified parent.
768                 /// </summary>
769                 /// <param name="pentry">
770                 /// The parent to which you want to move this entry
771                 /// </param>
772                 public void MoveTo(DirectoryEntry newParent)
773                 {
774                         string oldParentFdn = Parent.Fdn;
775                         conn.Rename(Fdn, Name, newParent.Fdn, true);
776                         // TBD : threat multiple name instance in path
777                         Path = Path.Replace(oldParentFdn,newParent.Fdn);
778                         RefreshEntry();                 
779                 }
780
781                 /// <summary>
782                 /// Moves this entry to the specified parent and changes its name to 
783                 /// the value of the newName parameter.
784                 /// </summary>
785                 /// <param name="newParent"> The parent to which you want to move 
786                 /// this entry
787                 /// </param>
788                 /// <param name="newName">
789                 /// The new name of this entry. 
790                 /// </param>
791                 public void MoveTo(     DirectoryEntry newParent,
792                                                         string newName  )
793                 {
794                         string oldParentFdn = Parent.Fdn;
795                         conn.Rename(Fdn, newName, newParent.Fdn, true);
796                         // TBD : threat multiple name instance in path
797                         Path = Path.Replace(oldParentFdn,newParent.Fdn).Replace(Name,newName);
798                         RefreshEntry(); 
799                 }
800
801                 /// <summary>
802                 /// Changes the name of this entry.
803                 /// </summary>
804                 /// <param name="newName">
805                 /// The new name of the entry. 
806                 /// </param>
807                 /// <remarks>
808                 /// Note   This will also affect the path used to refer to this entry.
809                 /// </remarks>
810                 public void Rename(     string newName  )
811                 {
812                         string oldName = Name;
813                         conn.Rename( Fdn, newName, true);
814                         // TBD : threat multiple name instance in path
815                         Path = Path.Replace(oldName,newName);
816                         RefreshEntry(); 
817                 }
818
819                 /// <summary>
820                 /// Calls a method on the native Active Directory.
821                 /// </summary>
822                 /// <param name="methodName">The name of the method to invoke. 
823                 /// </param>
824                 /// <param name="args">
825                 /// An array of type Object that contains the arguments of the method 
826                 /// to invoke. 
827                 /// </param>
828                 /// <returns>The return value of the invoked method</returns>
829                 /// <remarks>
830                 /// Not implemented.
831                 [MonoTODO]
832                 public object Invoke(string methodName,
833                         params object[] args)
834                 {
835                         throw new NotImplementedException();
836                 }
837
838                 /// <summary>
839                 /// Creates a copy of this entry, as a child of the specified parent, with 
840                 /// the specified new name.
841                 /// </summary>
842                 /// <param name="newParent">The parent DirectoryEntry.  </param>
843                 /// <param name="newName"> The name of the copy of this entry. 
844                 /// </param>
845                 /// <returns>A renamed copy of this entry as a child of the specified parent.
846                 [MonoTODO]
847                 public DirectoryEntry CopyTo( DirectoryEntry newParent,
848                         string newName  )
849                 {
850                         throw new NotImplementedException();
851                 }
852
853                 /// <summary>
854                 /// Saves any changes to the entry in the Ldap Directory store.
855                 /// </summary>
856                 /// <remarks>
857                 /// By default, changes to properties are done locally to a cache, and 
858                 /// property values to be read are cached after the first read. For more 
859                 /// information, see UsePropertyCache.
860                 /// Changes made to the cache include changes to the properties as well as 
861                 /// calls to Add (if this is the newly created entry).
862                 /// </remarks>
863                 public void CommitChanges()
864                 {
865                         if(UsePropertyCache) \r
866                         {\r
867                                 CommitEntry();\r
868                         }\r
869                 }\r
870 \r
871                 private void CommitEntry()\r
872                 {
873                         if(!Nflag)
874                         {
875                                 System.Collections.ArrayList modList = new System.Collections.ArrayList();
876                                 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
877                                 while(id.MoveNext())
878                                 {
879                                         string attribute=(string)id.Key;
880                                         LdapAttribute attr=null;
881                                         if(Properties[attribute].Mbit)
882                                         {
883                                                 if(Properties[attribute].Count==1)
884                                                 {
885                                                         String val = (String)Properties[attribute].Value;
886                                                         attr = new LdapAttribute( attribute , val);
887                                                 }
888                                                 else
889                                                 {
890                                                         Object[] vals=(Object [])Properties[attribute].Value;
891                                                         String[] aStrVals= new String[Properties[attribute].Count];
892                                                         Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
893                                                         attr = new LdapAttribute( attribute , aStrVals);
894                                                 }
895                                                 modList.Add( new LdapModification(LdapModification.REPLACE, attr));
896                                                 Properties[attribute].Mbit=false;
897                                         }
898                                 }
899                                 if (modList.Count > 0) {
900                                         LdapModification[] mods = new LdapModification[modList.Count];  
901                                         Type mtype=Type.GetType("System.DirectoryServices.LdapModification");
902                                         mods = (LdapModification[])modList.ToArray(typeof(LdapModification));
903                                         ModEntry(mods);
904                                 }
905                         }
906                         else
907                         {
908                                 LdapAttributeSet attributeSet = new LdapAttributeSet();
909                                 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
910                                 while(id.MoveNext())
911                                 {
912                                         string attribute=(string)id.Key;
913                                         if(Properties[attribute].Count==1)
914                                         {
915                                                 String val = (String)Properties[attribute].Value;
916                                                 attributeSet.Add(new LdapAttribute(attribute, val));                
917                                         }
918                                         else
919                                         {
920                                                 Object[] vals=(Object [])Properties[attribute].Value;
921                                                 String[] aStrVals= new String[Properties[attribute].Count];
922                                                 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
923                                                 attributeSet.Add( new LdapAttribute( attribute , aStrVals));
924                                         }
925                                 }
926                                 LdapEntry newEntry = new LdapEntry( Fdn, attributeSet );
927                                 conn.Add( newEntry );
928                                 Nflag = false;
929                         }
930                 }
931
932                 internal void CommitDeferred()\r
933                 {\r
934                         if (!_inPropertiesLoading && !UsePropertyCache && !Nflag) \r
935                         {\r
936                                 CommitEntry();\r
937                         }\r
938                 }
939
940                 void RefreshEntry()
941                 {
942                         _Properties = null;
943                         _Fdn = null;
944                         _Name = null;
945                         _Parent = null;
946                         _SchemaClassName = null;
947                         InitEntry();
948                 }
949
950                 [MonoTODO]
951                 public void RefreshCache ()
952                 {
953                         throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache()");
954                 }
955
956                 [MonoTODO]
957                 public void RefreshCache (string[] args)
958                 {
959                         throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache(System.String[])");
960                 }
961
962                 protected override void Dispose (bool disposing)
963                 {
964                         if (disposing) {
965                                 Close ();
966                         }
967                         base.Dispose (disposing);
968                 }
969         }
970 }