context: /*****************************************************************************
  *
  * Copyright (c) [2009] Novell, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, contact Novell, Inc.
  *
  * To contact Novell about this file by physical or electronic mail,
  * you may find current contact information at www.novell.com
  *
  *-----------------------------------------------------------------------------
  *
  *                 $Author: Calvin Gaisford <cgaisford@novell.com>
  *                 $Modified by: <Modifier>
  *                 $Mod Date: <Date Modified>
  *                 $Revision: 0.1
  *-----------------------------------------------------------------------------
  * This module is used to:
  *        <Description of the functionality of the file >
  *
  *
  *******************************************************************************/
  
  
  using System;
  using System.Collections;
  using System.ComponentModel;
  using System.Data;
  using System.Diagnostics;
  using System.Net;
  using System.Text;
  using System.Threading;
  using System.Web;
  using System.Web.Services;
  using System.Web.Services.Protocols;
  using System.IO;
  using System.Xml;
  using System.Xml.Serialization;
  using System.Security.Cryptography;
  
  //using Novell.Security.ClientPasswordManager;
  
  using Simias;
  using Simias.Authentication;
  using Simias.Client;
  using Simias.DomainServices;
  using Simias.Storage;
  using Simias.CryptoKey;
  using Simias.Sync;
  using Simias.Security.Web.AuthenticationService;
  //using Simias.POBox;
  
  namespace Simias.Web
  {
  
          /// <summary>
          /// Class used to keep track of outstanding searches.
          /// </summary>
          internal class SearchState : IDisposable
          {
                  #region Class Members
                  /// <summary>
                  /// Table used to keep track of outstanding search entries.
                  /// </summary>
                  static private Hashtable searchTable = new Hashtable();
   
                  /// <summary>
                  /// Indicates whether the object has been disposed.
                  /// </summary>
                  private bool disposed = false;
   
                  /// <summary>
                  /// Handle used to store and recall this context object.
                  /// </summary>
                  private string contextHandle = Guid.NewGuid().ToString();
   
                  /// <summary>
                  /// Identifier for the domain that is being searched.
                  /// </summary>
                  private string domainID;
   
                  /// <summary>
                  /// Object used to iteratively return the members from the domain.
                  /// </summary>
                  private ICSEnumerator enumerator;
   
                  /// <summary>
                  /// Total number of records contained in the search.
                  /// </summary>
                  private int totalRecords;
   
                  /// <summary>
                  /// The cursor for the caller.
                  /// </summary>
                  private int currentRecord = 0;
   
                  /// <summary>
                  /// The last count of records returned.
                  /// </summary>
                  private int previousCount = 0;
                  #endregion
                  #region Properties
                  /// <summary>
                  /// Indicates if the object has been disposed.
                  /// </summary>
                  public bool IsDisposed
                  {
                          get { return disposed; }
                  }
   
                  /// <summary>
                  /// Gets the context handle for this object.
                  /// </summary>
                  public string ContextHandle
                  {
                          get { return contextHandle; }
                  }
   
                  /// <summary>
                  /// Gets or sets the current record.
                  /// </summary>
                  public int CurrentRecord
                  {
                          get { return currentRecord; }
                          set { currentRecord = value; }
                  }
   
                  /// <summary>
                  /// Gets the domain ID for the domain that is being searched.
                  /// </summary>
                  public string DomainID
                  {
                          get { return domainID; }
                  }
   
                  /// <summary>
                  /// Gets or sets the last record count.
                  /// </summary>
                  public int LastCount
                  {
                          get { return previousCount; }
                          set { previousCount = value; }
                  }
   
                  /// <summary>
                  /// Gets the search iterator.
                  /// </summary>
                  public ICSEnumerator Enumerator
                  {
                          get { return enumerator; }
                  }
   
                  /// <summary>
                  /// Gets the total number of records contained by this search.
                  /// </summary>
                  public int TotalRecords
                  {
                          get { return totalRecords; }
                  }
                  #endregion
   
                  #region Constructor
                  /// <summary>
                  /// Initializes an instance of an object.
                  /// </summary>
                  /// <param name="domainID">Identifier for the domain that is being searched.</param>
                  /// <param name="enumerator">Search iterator.</param>
                  /// <param name="totalRecords">The total number of records contained in the search.</param>
                  public SearchState( string domainID, ICSEnumerator enumerator, int totalRecords )
                  {
                          this.domainID = domainID;
                          this.enumerator = enumerator;
                          this.totalRecords = totalRecords;
   
                          lock ( searchTable )
                          {
                                  searchTable.Add( contextHandle, this );
                          }
                  }
                  #endregion
   
                  #region Private Methods
                  /// <summary>
                  /// Removes this SearchState object from the search table.
                  /// </summary>
                  private void RemoveSearchState()
                  {
                          lock ( searchTable )
                          {
                                  // Remove the search context from the table and dispose it.
                                  searchTable.Remove( contextHandle );
                          }
                  }
                  #endregion
   
                  #region Public Methods
                  /// <summary>
                  /// Returns a search context object that contains the state information for an outstanding search.
                  /// </summary>
                  /// <param name="contextHandle">Context handle that refers to a specific search context object.</param>
                  /// <returns>A SearchState object if a valid one exists, otherwise a null is returned.</returns>
                  static public SearchState GetSearchState( string contextHandle )
                  {
                          lock ( searchTable )
                          {
                                  return searchTable[ contextHandle ] as SearchState;
                          }
                  }
                  #endregion
   
                  #region IDisposable Members
                  /// <summary>
                  /// Allows for quick release of managed and unmanaged resources.
                  /// Called by applications.
                  /// </summary>
                  public void Dispose()
                  {
                          RemoveSearchState();
                          Dispose( true );
                          GC.SuppressFinalize( this );
                  }
   
                  /// <summary>
                  /// Dispose( bool disposing ) executes in two distinct scenarios.
                  /// If disposing equals true, the method has been called directly
                  /// or indirectly by a user's code. Managed and unmanaged resources
                  /// can be disposed.
                  /// If disposing equals false, the method has been called by the
                  /// runtime from inside the finalizer and you should not reference
                  /// other objects. Only unmanaged resources can be disposed.
                  /// </summary>
                  /// <param name="disposing">Specifies whether called from the finalizer or from the application.</param>
                  private void Dispose( bool disposing )
                  {
                          // Check to see if Dispose has already been called.
                          if ( !disposed )
                          {
                                  // Protect callers from accessing the freed members.
                                  disposed = true;
   
                                  // If disposing equals true, dispose all managed and unmanaged resources.
                                  if ( disposing )
                                  {
                                          // Dispose managed resources.
                                          enumerator.Dispose();
                                  }
                          }
                  }
   
                  /// <summary>
                  /// Use C# destructor syntax for finalization code.
                  /// This destructor will run only if the Dispose method does not get called.
                  /// It gives your base class the opportunity to finalize.
                  /// Do not provide destructors in types derived from this class.
                  /// </summary>
                  ~SearchState()
                  {
                          Dispose( false );
                  }
                  #endregion
          }
  
  
  	/// <summary>
  	/// Supported store search operators.
  	/// </summary>
  	public enum SearchType
  	{
  		/// <summary>
  		/// Used to compare if two values are equal.
  		/// </summary>
  		Equal,
  
  		/// <summary>
  		/// Used to compare if two values are not equal.
  		/// </summary>
  		Not_Equal,
  
  		/// <summary>
  		/// Used to compare if a string value begins with a sub-string value.
  		/// </summary>
  		Begins,
  
  		/// <summary>
  		/// Used to compare if a string value ends with a sub-string value.
  		/// </summary>
  		Ends,
  
  		/// <summary>
  		/// Used to compare if a string value contains a sub-string value.
  		/// </summary>
  		Contains,
  
  		/// <summary>
  		/// Used to compare if a value is greater than another value.
  		/// </summary>
  		Greater,
  
  		/// <summary>
  		/// Used to compare if a value is less than another value.
  		/// </summary>
  		Less,
  
  		/// <summary>
  		/// Used to compare if a value is greater than or equal to another value.
  		/// </summary>
  		Greater_Equal,
  
  		/// <summary>
  		/// Used to compare if a value is less than or equal to another value.
  		/// </summary>
  		Less_Equal,
  
  		/// <summary>
  		/// Used to test for existence of a property.
  		/// </summary>
  		Exists,
  
  		/// <summary>
  		/// Used to do a case sensitive compare.
  		/// </summary>
  		CaseEqual
  	};
  
  	/// <summary>
  	/// Class that represents a member that has rights to a collection.
  	/// </summary>
  	[ Serializable ]
  	public class MemberInfo
  	{
  		/// <summary>
  		/// </summary>
  		public string	ObjectID;
  
  		/// <summary>
  		/// The user identitifer for this object.
  		/// </summary>
  		public string 	UserID;
  
  		/// <summary>
  		/// </summary>
  		public string	Name;
  
  		/// <summary>
  		/// the member's given (first) name
  		/// or null if the property is not present.
  		/// </summary>
  		public string	GivenName;
  
  		/// <summary>
  		/// The member's family (last) name
  		/// or null if the property is not present.
  		/// </summary>
  		public string	FamilyName;
  
  		/// <summary>
  		/// The member's full name
  		/// or null if the property is not present.
  		/// </summary>
  		public string	FullName;
  
  		/// <summary>
  		/// The members's access rights.
  		/// </summary>
  		public int	AccessRights;
  
  		/// <summary>
  		/// Whether this Member object is the collection owner.
  		/// </summary>
  		public bool	IsOwner;
  
  
  		/// <summary>
  		/// Whether this Member object is a user object.
  		/// </summary>
  		public bool	IsHost;
  
   		/// <summary>
  		/// Property tag for User object.
   		/// </summary>
  	        static private readonly string HostTag = "Host";
  
  		/// <summary>
  		/// </summary>
  		public MemberInfo()
  		{
  		}
  
  		//[ NonSerializable ]
  		internal MemberInfo( Simias.Storage.Member member )
  		{
  			this.Name = member.Name;
  			this.ObjectID = member.ID;
  			this.UserID = member.UserID;
  			this.GivenName = member.Given;
  			this.FamilyName = member.Family;
  			this.FullName = member.FN;
  			this.AccessRights = (int) member.Rights;
  			this.IsOwner = member.IsOwner;
  			this.IsHost = member.IsType (HostTag);
  		}
  	}
  
          [ Serializable ]
          public class NodeEntrySet
          {
                  public NodeEntry[] Items;
                  public long Count;
   
                  public NodeEntrySet()
                  {
                  }
   
                  public NodeEntrySet(NodeEntry[] list, long count)
                  {
                          this.Items = list;
                          this.Count = count;
                  }
          }
  
          /// <summary>
          /// Class that represents a member that has rights to a collection.
          /// </summary>
          [ Serializable ]
          public class NodeEntry
          {
                  public string ID;
                  public string Name;
                  public long Length;
                  public string Type;
                  public string RelativePath;
   
                  public NodeEntry()
                  {
                  }
   
                  public NodeEntry( Node n)
                  {
                          try
                          {
                                  this.ID = n.ID;
                                  this.Type = n.Type;
                                  this.Name = n.Name;
                                  if( this.Type == "FileNode")
                                  {
                                          this.Length = ((FileNode)n).Length;
                                          this.RelativePath = ((FileNode)n).GetRelativePath();
                                  }
                                  else if( this.Type == "DirNode")
                                  {
                                          this.Length = 0;
                                          this.RelativePath = ((DirNode)n).GetRelativePath();
                                  }
                          }
                          catch(Exception )
                          {
                          }
                  }
          }
  
  
  
  	/// <summary>
  	/// This is the core of the SimiasServce.  All of the methods in the
  	/// web service are implemented here.
  	/// </summary>
  	[WebService(
  	Namespace="http://novell.com/simias/web/",
  	Name="Simias Web Service",
  	Description="Web Service providing access to Simias")]
  	public class SimiasService : WebService
  	{
  		private static readonly ISimiasLog log = SimiasLogManager.GetLogger(typeof(SimiasService));
  		private static int simiasReferenceCount = 0;
  
  		private static string DomainServiceType = "Domain Service";
  		//private static string DomainServicePath = "/simias10/DomainService.asmx";
                  //private static string XmlFileRestore = "";
                  //private static string BasePathRestore = "";
                  private static Thread RestoreThread = null;
  
  
  		/// <summary>
  		/// Creates the SimiasService and sets up logging
  		/// </summary>
  		public SimiasService()
  		{
  		}
  
  		/// <summary>
  		/// WebMethod that allows a client to ping the service to see
  		/// if it is up and running
  		/// </summary>
  		[WebMethod(EnableSession=true, Description="Allows a client to ping to make sure the Web Service is up and running")]
  		[SoapDocumentMethod]
  		public void PingSimias()
  		{
  			// Nothing to do here, just return
  		}
  
  		/// <summary>
  		/// Add a member to a domain.
  		/// </summary>
  		/// <param name="DomainID">The ID of the domain to add the member to.</param>
  		/// <param name="MemberName">The name of the member.</param>
  		/// <param name="MemberID">The ID of the member.</param>
  		/// <param name="PublicKey">The public key for the member.</param>
  		/// <param name="GivenName">The given name for the member.</param>
  		/// <param name="FamilyName">The family name for the member.</param>
  		[WebMethod(EnableSession=true, Description="Add a member to the domain.")]
  		[SoapDocumentMethod]
  		public void AddMemberToDomain(string DomainID, string MemberName, string MemberID, string PublicKey, string GivenName, string FamilyName)
  		{
  			try
  			{
  				Domain domain = Store.GetStore().GetDomain( DomainID );
  				Simias.Storage.Member member = domain.GetMemberByName( MemberName );
  				if ( member == null )
  				{
  					bool given;
  					member = new Simias.Storage.Member( MemberName, MemberID, Access.Rights.ReadOnly );
  
  					if ( PublicKey != null )
  					{
  						member.Properties.AddProperty( "PublicKey", PublicKey );
  					}
  
  					if ( GivenName != null && GivenName != "" )
  					{
  						member.Given = GivenName;
  						given = true;
  					}
  					else
  					{
  						given = false;
  					}
  
  					if ( FamilyName != null && FamilyName != "" )
  					{
  						member.Family = FamilyName;
  						if ( given == true )
  						{
  							member.FN = GivenName + " " + FamilyName;
  						}
  					}
  					log.Debug("SetPassPhrase - called");
  
  					domain.Commit( member );
  				}
  			}
  			catch{}
  		}
  
  		/// <summary>
  		/// Remove a member from a domain
  		/// </summary>
  		/// <param name="DomainID">The ID of the domain to remove the member from.</param>
  		/// <param name="MemberID">The ID of the member to remove.</param>
  		[WebMethod(EnableSession=true, Description="Remove a member from the domain.")]
  		[SoapDocumentMethod]
  		public void RemoveMemberFromDomain(string DomainID, string MemberID)
  		{
  			Domain domain = Store.GetStore().GetDomain(DomainID);
  			Simias.Storage.Member member = domain.GetMemberByID( MemberID );
  			if ( member != null )
  			{
  				domain.Commit( domain.Delete( member ) );
  			}
  		}
  
  
  
  		/// <summary>
  		/// End the search for domain members.
  		/// </summary>
  		/// <param name="domainID">The identifier of the domain.</param>
  		/// <param name="searchContext">Domain provider specific search context returned by FindFirstMembers
  		/// or FindFirstSpecificMembers methods.</param>
  		[WebMethod(EnableSession=true, Description="End the search for domain members.")]
  		[SoapDocumentMethod]
  		public void FindCloseMembers( string domainID, string searchContext )
  		{
  			DomainProvider.FindCloseDomainMembers( domainID, searchContext );
  		}
  
  
  
  		/// <summary>
  		/// Starts a search for all domain members.
  		/// </summary>
  		/// <param name="domainID">The identifier of the domain to search for members in.</param>
  		/// <param name="count">Maximum number of member objects to return.</param>
  		/// <param name="searchContext">Receives a provider specific search context object.</param>
  		/// <param name="memberList">Receives an array object that contains the domain Member objects.</param>
  		/// <param name="totalMembers">Receives the total number of objects found in the search.</param>
  		/// <returns>True if there are more domain members. Otherwise false is returned.</returns>
  		[WebMethod(EnableSession=true, Description="Starts a search for all domain members.")]
  		[SoapDocumentMethod]
  		public bool FindFirstMembers( 
  			string domainID, 
  			int count,
  			out string searchContext, 
  			out MemberInfo[] memberList, 
  			out int totalMembers )
  		{
  			Member[] tempList;
  
  			bool moreEntries = 
  				DomainProvider.FindFirstDomainMembers(
  					domainID, 
  					count,
  					out searchContext, 
  					out tempList, 
  					out totalMembers );
  
  			if ( ( tempList != null ) && ( tempList.Length > 0 ) )
  			{
  				memberList = new MemberInfo[ tempList.Length ];
  				for ( int i = 0; i < tempList.Length; ++i )
  				{
  					memberList[ i ] = new MemberInfo( tempList[ i ] );
  				}
  			}
  			else
  			{
  				memberList = null;
  			}
  
  			return moreEntries;
  		}
  
  
  
  		/// <summary>
  		/// Starts a search for a specific set of domain members.
  		/// </summary>
  		/// <param name="domainID">The identifier of the domain to search for members in.</param>
  		/// <param name="attributeName">Attribute name to search.</param>
  		/// <param name="searchString">String that contains a pattern to search for.</param>
  		/// <param name="operation">Type of search operation to perform.</param>
  		/// <param name="count">Maximum number of member objects to return.</param>
  		/// <param name="searchContext">Receives a provider specific search context object.</param>
  		/// <param name="memberList">Receives an array object that contains the domain Member objects.</param>
  		/// <param name="totalMembers">Receives the total number of objects found in the search.</param>
  		/// <returns>True if there are more domain members. Otherwise false is returned.</returns>
  		[WebMethod(EnableSession=true, Description="Starts a search for a specific set of domain members.")]
  		[SoapDocumentMethod]
  		public bool FindFirstSpecificMembers(
  			string domainID, 
  			string attributeName, 
  			string searchString, 
  			SearchType operation, 
  			int count,
  			out string searchContext, 
  			out MemberInfo[] memberList, 
  			out int totalMembers )
  		{
  			Member[] tempList;
  
  			bool moreEntries = 
  				DomainProvider.FindFirstDomainMembers(
  					domainID,
  					attributeName,
  					searchString,
  					( Simias.Storage.SearchOp )Enum.ToObject( typeof( Simias.Storage.SearchOp ), operation ),
  					count,
  					out searchContext, 
  					out tempList, 
  					out totalMembers );
  
  			if ( ( tempList != null ) && ( tempList.Length > 0 ) )
  			{
  				memberList = new MemberInfo[ tempList.Length ];
  				for ( int i = 0; i < tempList.Length; ++i )
  				{
  					memberList[ i ] = new MemberInfo( tempList[ i ] );
  				}
  			}
  			else
  			{
  				memberList = null;
  			}
  
  			return moreEntries;
  		}
  
  
  
  		/// <summary>
  		/// Continues the search for domain members from the current record location.
  		/// </summary>
  		/// <param name="domainID">The identifier of the domain to search for members in.</param>
  		/// <param name="searchContext">Domain provider specific search context returned by 
  		/// FindFirstMembers or FindFirstSpecificMembers methods.</param>
  		/// <param name="count">Maximum number of member objects to return.</param>
  		/// <param name="memberList">Receives an array object that contains the domain Member objects.</param>
  		/// <returns>True if there are more domain members. Otherwise false is returned.</returns>
  		[WebMethod(EnableSession=true, Description="Continues the search for domain members from the current record location.")]
  		[SoapDocumentMethod]
  		public bool FindNextMembers( 
  			string domainID, 
  			ref string searchContext, 
  			int count,
  			out MemberInfo[] memberList )
  		{
  			Member[] tempList;
  
  			bool moreEntries = DomainProvider.FindNextDomainMembers( domainID, ref searchContext, count, out tempList );
  
  			if ( ( tempList != null ) && ( tempList.Length > 0 ) )
  			{
  				memberList = new MemberInfo[ tempList.Length ];
  				for ( int i = 0; i < tempList.Length; ++i )
  				{
  					memberList[ i ] = new MemberInfo( tempList[ i ] );
  				}
  			}
  			else
  			{
  				memberList = null;
  			}
  
  			return moreEntries;
  		}
  
  
  
  		/// <summary>
  		/// Continues the search for domain members previous to the current record location.
  		/// </summary>
  		/// <param name="domainID">The identifier of the domain to search for members in.</param>
  		/// <param name="searchContext">Domain provider specific search context returned by 
  		/// FindFirstMembers or FindFirstSpecificMembers methods.</param>
  		/// <param name="count">Maximum number of member objects to return.</param>
  		/// <param name="memberList">Receives an array object that contains the domain Member objects.</param>
  		/// <returns>True if there are more domain members. Otherwise false is returned.</returns>
  		[WebMethod(EnableSession=true, Description="Continues the search for domain members previous to the current record location.")]
  		[SoapDocumentMethod]
  		public bool FindPreviousMembers( 
  			string domainID, 
  			ref string searchContext, 
  			int count,
  			out MemberInfo[] memberList )
  		{
  			Member[] tempList;
  
  			bool moreEntries = DomainProvider.FindPreviousDomainMembers( domainID, ref searchContext, count, out tempList );
  
  			if ( ( tempList != null ) && ( tempList.Length > 0 ) )
  			{
  				memberList = new MemberInfo[ tempList.Length ];
  				for ( int i = 0; i < tempList.Length; ++i )
  				{
  					memberList[ i ] = new MemberInfo( tempList[ i ] );
  				}
  			}
  			else
  			{
  				memberList = null;
  			}
  
  			return moreEntries;
  		}
  
  
  
  
  		/// <summary>
  		/// Continues the search for domain members from the specified record location.
  		/// </summary>
  		/// <param name="domainID">The identifier of the domain to search for members in.</param>
  		/// <param name="searchContext">Domain provider specific search context returned by 
  		/// FindFirstMembers or FindFirstSpecificMembers method.</param>
  		/// <param name="offset">Record offset to return members from.</param>
  		/// <param name="count">Maximum number of member objects to return.</param>
  		/// <param name="memberList">Receives an array object that contains the domain Member objects.</param>
  		/// <returns>True if there are more domain members. Otherwise false is returned.</returns>
  		[WebMethod(EnableSession=true, Description="Continues the search for domain members from the specified record location.")]
  		[SoapDocumentMethod]
  		public bool FindSeekMembers( 
  			string domainID, 
  			ref string searchContext, 
  			int offset, 
  			int count, 
  			out MemberInfo[] memberList )
  		{
  			Member[] tempList;
  
  			bool moreEntries = DomainProvider.FindSeekDomainMembers( 
  				domainID, 
  				ref searchContext, 
  				offset, 
  				count, 
  				out tempList );
  
  			if ( ( tempList != null ) && ( tempList.Length > 0 ) )
  			{
  				memberList = new MemberInfo[ tempList.Length ];
  				for ( int i = 0; i < tempList.Length; ++i )
  				{
  					memberList[ i ] = new MemberInfo( tempList[ i ] );
  				}
  			}
  			else
  			{
  				memberList = null;
  			}
  
  			return moreEntries;
  		}
  
  
  
  		/// <summary>
  		/// WebMethod that returns the Simias information
  		/// </summary>
  		/// <returns>
  		/// string with Simias information
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="GetSimiasInformation")]
  		[SoapDocumentMethod]
  		public string GetSimiasInformation()
  		{
  			return "TODO: Implement the Simias Web Service";
  		}
  
  
  
  		/// <summary>
  		/// WebMethod to get information about a specified domain 
  		/// </summary>
  		/// <returns>
  		/// DomainInformation object
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="GetDomainInformation")]
  		[SoapDocumentMethod]
  		public
  		DomainInformation
  		GetDomainInformation(string domainID)
  		{
  			DomainInformation cDomainInfo = null;
  
  			try
  			{
  				cDomainInfo = new DomainInformation(domainID);
  			}
  			catch(Exception e)
  			{
  				log.Debug(e.Message);
  				log.Debug(e.StackTrace);
  				cDomainInfo = null;
  			}
  
  			return(cDomainInfo);
  		}
  
  
  
  		/// <summary>
  		/// WebMethod to get a list of local domains
  		/// </summary>
  		/// <returns>
  		/// DomainInformation objects
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="Get a list of local domains")]
  		[SoapDocumentMethod]
  		public
  		DomainInformation[]
  		GetDomains(bool onlySlaves)
  		{
  			ArrayList domains = new ArrayList();
  
  			try
  			{
  				Store store = Store.GetStore();
  				ICSList domainList = store.GetDomainList();
  				foreach( ShallowNode shallowNode in domainList )
  				{
  					try
  					{
  						// Get the information about this domain.
  						log.Debug("GetDomains: shallownode id is {0}",shallowNode.ID);
  						DomainInformation domainInfo = new DomainInformation(shallowNode.ID);
  						if ( ( ( onlySlaves == false ) &&
  							( domainInfo.Type.Equals( DomainType.Master ) || domainInfo.Type.Equals( DomainType.Slave ) ) ) ||
  							( domainInfo.Type.Equals( DomainType.Slave ) ) )
  						{
  							domains.Add(domainInfo);
  						}
  					}
  					catch(Exception e)
  					{
  						log.Error(e.Message);
  						log.Error(e.StackTrace);
  					}
  				}
  			}
  			catch(Exception e)
  			{
  				log.Error(e.Message);
  				log.Error(e.StackTrace);
  			}
  
  			return((DomainInformation[]) domains.ToArray(typeof(DomainInformation)));
  		}
  
  
  
  		/// <summary>
  		/// WebMethod to login or authenticate against a 
  		/// remote domain.  The user must have previously joined
  		/// or attached to this domain.
  		/// </summary>
  		/// <returns>
  		/// Simias.Client.Authentication.Status status
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="Login or authenticate to a remote domain")]
  		[SoapDocumentMethod]
  		public
  		Simias.Authentication.Status
  		LoginToRemoteDomain(string domainID, string password)
  		{ 
  			log.Debug( "LoginToRemoteDomain - called" );
  			Store store = Store.GetStore();
  			Simias.Storage.Domain domain = store.GetDomain(domainID);
  			if( domain == null )
  			{
  				return new Simias.Authentication.Status( Simias.Authentication.StatusCodes.UnknownDomain );
  			}
  
  			Simias.Storage.Member member = domain.GetCurrentMember();
  			if( member == null )
  			{
  				return new Simias.Authentication.Status( Simias.Authentication.StatusCodes.UnknownUser );
  			}
  
  			log.Debug( "  User: " + member.Name );
  
  			
  			DomainAgent domainAgent = new DomainAgent();
              Simias.Authentication.Status status = domainAgent.Login( domainID, member.Name, password );
              if( status.statusCode == Simias.Authentication.StatusCodes.Success)
              {
                   SyncClient.RescheduleAllColSync(domainID);
              }
              return status;
  		}
  
  
  
  		/// <summary>
  		/// WebMethod to logout from a remote domain.
  		/// The user must have previously joined and 
  		/// authenticated to this domain.
  		/// </summary>
  		/// <returns>
  		/// Simias.Client.Authentication.Status status
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="Logout from a remote domain")]
  		[SoapDocumentMethod]
  		public
  		Simias.Authentication.Status
  		LogoutFromRemoteDomain(string domainID)
  		{
  			return new DomainAgent().Logout(domainID);
  		}
  
  
  
  		/// <summary>
  		/// WebMethod to disable automatic authentication to a domain.
  		/// </summary>
  		/// <param name="domainID">The ID of the domain to disable automatic authentication to.</param>
  		[WebMethod(EnableSession=true, Description="Disable automatic authentication to the specified domain")]
  		[SoapDocumentMethod]
  		public void	DisableDomainAutoLogin(string domainID)
  		{
  			new DomainAgent().SetDomainState(domainID, false, false);
  		}
  
  
  
  
  		/// <summary>
  		/// WebMethod to check if a domain is "active"
  		/// </summary>
  		/// <param name = "domainID">
  		/// The specified domain to check
  		/// </param>
  		/// <returns>
  		/// 0 success, !0 failed
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="WebMethod to check if a domain is active")]
  		[SoapDocumentMethod]
  		public bool IsDomainActive(string domainID)
  		{
  			return( new DomainAgent().IsDomainActive( domainID ) );
  		}
  
  
  
  		/// <summary>
  		/// WebMethod to set a slave domain "active"
  		/// A Domain marked "active" will synchronize
  		/// collections, subscriptions etc. to the remote server
  		/// </summary>
  		/// <returns>
  		/// 0 success, !0 failed
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="SetDomainActive - enables synchronization to the remote server")]
  		[SoapDocumentMethod]
  		public int SetDomainActive(string domainID)
  		{
  			DomainAgent domainAgent = new DomainAgent();
  			domainAgent.SetDomainActive( domainID );
  			return(0);
  		}
  
  
  
  
  		/// <summary>
  		/// WebMethod to mark a slave domain "inactive"
  		/// Marking a domain inactive disables all synchronization
  		/// to the remote machine.
  		/// </summary>
  		/// <returns>
  		/// 0 success, !0 failed
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="SetDomainInactive - disables remote synchronization")]
  		[SoapDocumentMethod]
  		public int SetDomainInactive(string domainID)
  		{
  			DomainAgent domainAgent = new DomainAgent();
  			domainAgent.SetDomainInactive( domainID );
  			return(0);
  		}
  
  
  
  
  		/// <summary>
  		/// WebMethod that checks to see if a full set of credentials
  		/// has been set on a domain for a specified user
  		/// </summary>
  		/// <returns>
  		/// true - valid credentials for member on the domain, false
  		/// </returns>
  		[WebMethod(EnableSession=true, Description="ValidCredentials")]
  		[SoapDocumentMethod]
  		public
  		bool ValidCredentials(string domainID, string memberID)
  		{
  			bool status = false;
  			try
  			{
  
gt: 				Store store = Store.GetStore();