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