/*
ESUP-portail is a french academic project developed under the GPL (General Public License) augmented according to the following :
A binary or source file developped by ESUP-portail can be used or compiled with products under Apache license.
The official english text of the GPL can be found here : http://www.gnu.org/licenses/gpl.html .
A non official french translation can be found here : http://www.linux-France.org/article/these/gpl.html .
The different kinds of licenses governing the products developed by the Apache foundation can be found here : http://www.apache.org/licenses .
It follows that you can as well as use download contents as well modify and redistribute them provided you respect the GPL terms.
Downloading and using such contents do not provide any guaranty.
Be sure that you have well understood the terms of the license before using the contents it covers.
The ESUP-portail distribution includes the following distributions :
    * UPortal :
      software developed by JA-SIG (Java Architecture - Special Interest Group)
      You can find the license page here : http://mis105.udel.edu/ja-sig/uportal/license.html
    * CAS :
      SSO solution developed by Yale University
      You can find the project page here : http://www.yale.edu/tp/auth
    * Cocoon :
      XML framework distributed by the Apache foundation under Apache license;
      Please find the full text here : http://cocoon.apache.org/2.1/license.html
    * Mod_dav:
      A DAV module for Apache web server
      You can find the project page here : http://www.webdav.org/mod_dav
    * IMP :
      webmail from Horde application framework
      You can find the project page here : http://www.horde.org
    * ?. To be completed
*/

package org.esupportail.portal.channels.CStockage.provider.access;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Vector;

import jcifs.Config;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbAuthException;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.esupportail.portal.channels.CStockage.config.Space;
import org.esupportail.portal.channels.CStockage.exception.AclAccessException;
import org.esupportail.portal.channels.CStockage.exception.AclReadException;
import org.esupportail.portal.channels.CStockage.exception.AclWriteException;
import org.esupportail.portal.channels.CStockage.exception.ApplicationException;
import org.esupportail.portal.channels.CStockage.exception.BadConnexionParameters;
import org.esupportail.portal.channels.CStockage.exception.BadFormatException;
import org.esupportail.portal.channels.CStockage.exception.CopyException;
import org.esupportail.portal.channels.CStockage.exception.CreateDirectoryException;
import org.esupportail.portal.channels.CStockage.exception.DeleteException;
import org.esupportail.portal.channels.CStockage.exception.DownloadException;
import org.esupportail.portal.channels.CStockage.exception.EmptyFileOnUploadException;
import org.esupportail.portal.channels.CStockage.exception.MoveException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedDeleteException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedNewDirException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedRenameException;
import org.esupportail.portal.channels.CStockage.exception.NotAuthorizedUploadException;
import org.esupportail.portal.channels.CStockage.exception.NotExistsResourceException;
import org.esupportail.portal.channels.CStockage.exception.NotSupportedAclException;
import org.esupportail.portal.channels.CStockage.exception.OverQuotaException;
import org.esupportail.portal.channels.CStockage.exception.PasteDeletedResourceException;
import org.esupportail.portal.channels.CStockage.exception.PasteInChildDirectoryException;
import org.esupportail.portal.channels.CStockage.exception.PasteNotAuthorizedResourceException;
import org.esupportail.portal.channels.CStockage.exception.PasteWithSameNameException;
import org.esupportail.portal.channels.CStockage.exception.PropertiesException;
import org.esupportail.portal.channels.CStockage.exception.RenameException;
import org.esupportail.portal.channels.CStockage.exception.ServerException;
import org.esupportail.portal.channels.CStockage.exception.StillExistsException;
import org.esupportail.portal.channels.CStockage.exception.UploadException;
import org.esupportail.portal.channels.CStockage.provider.ChannelResource;
import org.esupportail.portal.channels.CStockage.provider.ResourceControl;
import org.esupportail.portal.utils.webdav.acl.EsupPermissions;


/**
 * Implements the ServerAccess interface to access a CIFS(SMB) server<br/>
 * <b>Id:</b> <code>CifsAccessImpl.java</code><br/>
 * <b>Classes:</b> <code>CifsAccessImpl</code><br/>
 * <b>Creation date:</b> 17/12/2004<br/>
 * <b>Last modification:</b> 24/02/2005<br/>
 * Modifications :<br/>
 * 24/02/2005 Thomas Bellembois Correcting some bugs
 * Copyright (c) 2004 Esup Portail (www.esup-portail.org).<br/>
 * 
 * <i>Notes</i> :
 * <lu>
 * <li>1. In this document the term <b>resource</b> refer to a directory or a file</li>
 * <li>2. An URI like <code>/myDirectory/mySubDirectory/myResource</code> is called <b>full path (of myResource)</b>
 * whereas an URI like <code>/myDirectory/mySubDirectory</code> is called <b>path (of myResource)</b></li>
 * <li>3. A resource (file/directory) can be written in many ways to call methods. For example you can write <code>/myResource</code>, 
 * or <code>/myResource/</code>, but also <code>myResource</code>. Even if the resource is a file you can write <code>/myFile.txt/</code> !</li>
 * </lu>
 * 
 * @author Thomas Bellembois
 * @version 1.2
 */

public class CifsAccessImpl extends ServerAccess{

	////////////////////
	// common parameters
	//
	// Logger object
	protected static final Log log = LogFactory.getLog(CifsAccessImpl.class);
	// Const.
	private static final int LOG_DEBUG = 0;
	private static final int LOG_INFO = 1;
	private static final int LOG_WARN = 2;
	private static final int LOG_ERROR = 3;
	
	private static final int RESSOURCE_FILEORFOLDER_NAME = 0;
	private static final int RESSOURCE_FILE_PATH = 1;
	private static final int RESSOURCE_FOLDER_PATH = 2;
	private static final int RESSOURCE_UNKNOWN_PATH = 3;
	private static final int RESSOURCE_URI = 4;
	
	private static final int INPUTSTREAM_BUFFER = 512000;
	
	/////////////////////////
	// CIFS server parameters
	//
	private String uri;				// CIFS server uri - ex : smb://mySmbServer	
	private String resourcePath; 	// The resource path - ex : /myHomeDir/myFirstDir/myFile.txt /myHomeDir/myFirstDir/
	// details about following parameters available at http://jcifs.samba.org/
	private String domain; 			// Domain
	private String login; 			// User login
	private String password; 		// User password
	private String resolveOrder; 	// resolveOrder parameter
	private NtlmPasswordAuthentication ntlmPasswordAuthentication; 	// User credential
	private String disablePlainTextPassword; 						// disablePlainTextPassword parameter

	private SmbFile smbFile; 		// CIFS current smbFile (i.e. the resource we are working on)
	
	
	/////////////////////////////////
	// log the message in "type" mode
	//
	private void logMethod(int type, String message){
		if(type == LOG_DEBUG && log.isDebugEnabled()){
			log.debug(message);
		}// LOG_DEBUG
		else if(type == LOG_INFO){
			log.info(message);
		}// LOG_INFO
		else if(type == LOG_WARN){
			log.warn(message);
		}// LOG_WARN
		else if(type == LOG_ERROR){
			log.warn(message);
		}// LOG_ERROR
	}// log
	
	
	////////////////////////////////////////////////////
	// Method used to normalize resource names and paths
	// This method only processes '/' characters
	private String normalizeResourceUri (String stringToProcess, int ressourceType) {
		String result = null;
			switch (ressourceType){
				case RESSOURCE_FILEORFOLDER_NAME : 
					// a file or folder NAME must not contain any '/'
					if (stringToProcess.endsWith("/")) {
						stringToProcess = stringToProcess.substring(0, stringToProcess.length()-1); // removing the ending '/'
					}// if (stringToProcess.endsWith("/"))
					if (stringToProcess.startsWith("/")) {
						stringToProcess = stringToProcess.substring(1); // removing the begining '/'
					}// if (stringToProcess.startsWith("/"))
					return stringToProcess;
				case RESSOURCE_FOLDER_PATH :
					// a folder PATH must contain a begining and ending '/'
					if (!stringToProcess.endsWith("/")) {
						stringToProcess = stringToProcess.concat("/");
					}// if (!stringToProcess.endsWith("/"))
					if (!stringToProcess.startsWith("/")) {
						stringToProcess = "/".concat(stringToProcess);
					}// if (!stringToProcess.startsWith("/"))
					return stringToProcess;
				case RESSOURCE_FILE_PATH :
					// a folder PATH must contain a begining and no ending '/'
					if (!stringToProcess.startsWith("/")) {
						stringToProcess = "/".concat(stringToProcess);
					}// if (!stringToProcess.startsWith("/"))
					if (stringToProcess.endsWith("/")) {
						stringToProcess = stringToProcess.substring(0, stringToProcess.length()-1); // removing the ending '/'
					}// if (stringToProcess.endsWith("/"))
					return stringToProcess;
				case RESSOURCE_UNKNOWN_PATH :
					// a file or folder PATH must contain at least a begining '/'
					if (!stringToProcess.startsWith("/")) {
						stringToProcess = "/".concat(stringToProcess);
					}// if (!stringToProcess.startsWith("/"))
					return stringToProcess;
				case RESSOURCE_URI :
					// an uri must not contain an ending '/'
					if (stringToProcess.endsWith("/")) {
						stringToProcess = stringToProcess.substring(0, stringToProcess.length()-1); // removing the ending '/'
					}// if (stringToProcess.endsWith("/"))
					return stringToProcess;
			}// switch (ressourceType)
			
		return result;
		
	}// normalizeResourceUri
	
	
	/**
     * Initializes the CIFS server parameters<br>
     * You have to call this method before calling the connect method.<br>
     * <i>About Space parameters :</i><br>
     * A lot of parameters could be used to configure the access to the CIFS server. But only the more required parameters are used by this class.<br>
     * For more details about all the available parameters, refer to the JCIFS documentation at <code>http://jcifs.samba.org/src/docs/api/</code><br>
     * <lu>
     * <li><code>login</code> : login to connect to the server</li>
     * <li><code>password</code> : password to connect to the server</li>
     * <li><code>uri</code> : URL of the CIFS server - <i>example</i> : smb://myServer:myPort</li>
     * <li><code>resourcePath</code> : resource full path on the CIFS server - <i>example</i> : /myHomeDir/myDirectory/myFile.txt</li>
     * <li><code>domain</code> : domain of the CIFS server</li>
     * <li><code>resolveOrder</code> : A comma separated list of name resolution method identifiers that specify which methods will be used and in what order to resolve hostnames. The possible identifiers in default order are LMHOSTS, WINS, BCAST, and DNS.</li>
     * <li><code>disablePlainTextPassword</code> : Plain text passwords should never be used and are disabled by default. To enable jCIFS to use plain text password this property must be set to false.</li>
     * </lu>
     * @param space space used to get connexion parameters
     * @throws MalformedURLException
     * @throws PropertiesException
     */
	public void init(Space space) throws MalformedURLException, PropertiesException {
		
		logMethod(LOG_DEBUG, "> Entering init");
		
		//////////////////////////////////////
		// Initializing CIFS server parameters
		//
		this.login = space.getLogin();
		this.password = space.getPassword();
		this.uri = space.getUrl();
		this.resourcePath = space.getCurrentPath();
		this.domain = space.getCifsDomain();
		this.resolveOrder = space.getCifsResolveOrder();
		this.disablePlainTextPassword = space.getCifsDisablePlainTextPassword();
		
		//////////////////////////////
		// normalizing the parameters
		//
		uri = normalizeResourceUri(uri, RESSOURCE_URI);
		resourcePath = normalizeResourceUri(resourcePath, RESSOURCE_FOLDER_PATH);

		logMethod(LOG_DEBUG, "> init :: uri="+uri+" resourcePath="+resourcePath+" login="+login);
		
		////////////////////////////////////
		// Configuring the server parameters
		//
		if (domain!=null)
			Config.setProperty("jcifs.smb.client.domain", domain);
		if (resolveOrder!=null)
			Config.setProperty("jcifs.resolveOrder", resolveOrder);
		if (disablePlainTextPassword!=null)
			Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", disablePlainTextPassword);
		Config.setProperty("jcifs.smb.client.responseTimeout", "40000");
				
		//////////////////////////
		// Building the credential
		//
		this.ntlmPasswordAuthentication = new NtlmPasswordAuthentication(domain, login, password);
		
		///////////////////////
		// Building the smbFile
		//
		smbFile = new SmbFile(uri+resourcePath, ntlmPasswordAuthentication);
		
	}// init

	
	/**
	 * Returns the current path on the server<br>
	 * <i>Example</i> : if the current server url is <code>smb://URL:PORT/test</code>, the current path is <code>/test</code>
	 * @return the current path as a String
	 * @throws MalformedURLException
	 */
	/*public String getServerCurrentHierPath() throws MalformedURLException {
		
		logMethod(LOG_DEBUG, "> Entering getServerCurrentHierPath");
		// getting the current path
		String currentHierPath = (smbFile.getPath()).substring(uri.length());
		logMethod(LOG_DEBUG, "getServerCurrentHierPath :: currentHierPath="+currentHierPath);
		if (currentHierPath == null) currentHierPath = "";
		return currentHierPath;
		
	}*/// getServerCurrentHierPath

	
	/**
	 * Connect to the server	 
	 * @throws ServerException
	 * @throws BadConnexionParameters
	 */
	public void connect() throws ServerException, BadConnexionParameters {
		
		logMethod(LOG_DEBUG, "> Entering connect");
		try {
			smbFile.exists();
		} catch (SmbAuthException e) {
			// the WebDAV channel requires to catch a BadConnexionParameters exception if a bad password is entered
			if (e.getNtStatus() == SmbException.NT_STATUS_WRONG_PASSWORD) {
				logMethod(LOG_ERROR, "connect"+" :: bad password ");
				throw new BadConnexionParameters();
			}// if (e1.getNtStatus() == SmbException.NT_STATUS_WRONG_PASSWORD)	
			else if (e.getNtStatus() == SmbException.NT_STATUS_LOGON_FAILURE) {
				logMethod(LOG_ERROR, "connect"+" :: bad login ");
				throw new BadConnexionParameters();
			}// if (e1.getNtStatus() == SmbException.NT_STATUS_WRONG_PASSWORD)	
			else {
				logMethod(LOG_ERROR, "connect"+" :: "+e);
				throw new ServerException();
			}// else (e1.getNtStatus() == SmbException.NT_STATUS_WRONG_PASSWORD)
		}
		catch (SmbException e1) {
			logMethod(LOG_ERROR, "connect"+" :: "+e1);
			throw new ServerException();
		}
		
	}// connect

	
	/**
	 * Disconnect from the server
	 * @throws ServerException
	 */
	public void disconnect() throws ServerException {
		
		logMethod(LOG_DEBUG, "> Entering disconnect");
		
	}// disconnect

	
	/**
	 * List all the resources of a directory
	 * @param fullPath full path of the directory to list
	 * @return the list of resources as an array of ChannelWebdavResource
	 * @throws NotExistsResourceException
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */	
	public ChannelResource[] ls(String fullPath) throws NotExistsResourceException, ApplicationException, NotAuthorizedException {
	
		logMethod(LOG_DEBUG, "> Entering ls :: fullPath="+fullPath);
		
		//////////////////////////////
		// normalizing the parameters
		//
		fullPath = normalizeResourceUri(fullPath, RESSOURCE_FOLDER_PATH);
		
		/////////////
		// variables
		//
		// the result
		ChannelResource [] channelResource = null;
		// properties required to build the result
		String displayName;
		String path;
		long contentLength;
		String contentType;
		long lastModified;
		boolean isCollection;
		InputStream inputStream;
		
		////////////////////////////////////////////////////////
		// checking that the full path exists and is a directory
		//
		if (! exists(fullPath)) {
			logMethod(LOG_DEBUG, "ls"+" :: fullPath="+fullPath+"  does not exist");
			throw new NotExistsResourceException();
		}// if (! exists(fullPath, path))
		else {
			// the full path exist, checking that it is a directory
			boolean fullPathIsDirectory = false;
			try {
				smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
				fullPathIsDirectory = smbFile.isDirectory();
			} catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "ls"+" :: "+e);
				throw new ApplicationException();
			} catch (SmbException e1) {
				logMethod(LOG_ERROR, "ls"+" :: "+e1);
				throw new ApplicationException();
			}
			
			if (!fullPathIsDirectory) {
				logMethod(LOG_DEBUG, "ls"+" :: fullPath="+fullPath+"  is not a directory");
				throw new ApplicationException();
			}// if (!fullPathIsDirectory)
			else{
				/////////////////////////////////////////////////
				// the full path is a directory, we can do the ls
				//
				try {					
					// getting the children of the resource
					SmbFile [] children = smbFile.listFiles();
					
					// initializing the result
					channelResource = new ChannelResource [children.length];
					
					// for each children gathering required information, building a ChannelResource and adding it to the result
					logMethod(LOG_DEBUG, "ls"+" :: gathering children information for "+fullPath);
					for (int i=0; i<children.length; i++){
						
						displayName = children[i].getName();
						// the returned display name contains a ending '/' if the resource is a directory
						displayName = normalizeResourceUri(displayName, RESSOURCE_FILEORFOLDER_NAME);
						logMethod(LOG_DEBUG, "ls"+" :: gathering information for "+displayName);
						path = children[i].getPath();
						contentLength = children[i].getContentLength();
						lastModified = children[i].getLastModified();
						isCollection = children[i].isDirectory();
						contentType = URLConnection.guessContentTypeFromName(displayName);
//						if (!isCollection){
//							inputStream = children[i].getInputStream();
//						}// if (!isCollection)
//						else{
//							inputStream = null;
//						}// else (!isCollection)
												
						// the getPath() method return the full path like smb://myServer/myDirectory/myFile.txt
						// we only want to return something like /myDirectory/myFile.txt
						path = path.substring(uri.length());
										
						logMethod(LOG_DEBUG, "ls"+" :: adding "+displayName+" to the result");
						channelResource[i] = new ChannelResource(displayName, path, contentLength, contentType, lastModified, isCollection);
						
					}// for (int i=0; i<children.length; i++)
				} catch (SmbException e) {
					logMethod(LOG_ERROR, "ls"+" :: "+e);
					throw new ApplicationException();
				}
			}// else (!fullPathIsDirectory)
		}// else (! exists(fullPath))

		return channelResource;
	}// ls

	
	/**
	 * List all the resources of the given directory
	 * @param path path of the directory to list
	 * @param targetDirectory name of the directory to list
	 * @return the list of resources as an array of ChannelWebdavResource
	 * @throws NotExistsResourceException
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */		
	public ChannelResource[] ls(String path, String targetDirectory) throws NotExistsResourceException, ApplicationException, NotAuthorizedException {
		
		logMethod(LOG_DEBUG, "> Entering ls :: path="+path+" targetDirectory="+targetDirectory);
		
		// normalizing the parameters
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		targetDirectory = normalizeResourceUri(targetDirectory, RESSOURCE_FILEORFOLDER_NAME);
		
		// just calling the ls(fullPath) method
		return ls(path+targetDirectory);
	
	}// ls

	
	/**
	 * Upload a file to the path given in argument
	 * @param fileName the input file name
	 * @param fileStream the input file stream
	 * @param path the path
	 * @return boolean true if no problem, else false
	 * @throws ApplicationException
	 * @throws ServerException
	 * @throws NotExistsResourceException
	 * @throws StillExistsException
	 * @throws BadFormatException
	 * @throws UploadException
	 * @throws EmptyFileOnUploadException
	 * @throws OverQuotaException
	 * @throws NotAuthorizedDeleteException
	 * @throws NotAuthorizedUploadException
	 * @throws NotAuthorizedException
	 */	
	public boolean upload(String fileName, InputStream fileStream, String path) throws ApplicationException, ServerException, NotExistsResourceException, StillExistsException, BadFormatException, UploadException, EmptyFileOnUploadException, OverQuotaException, NotAuthorizedDeleteException, NotAuthorizedUploadException, NotAuthorizedException, PropertiesException {
		
		//////////////////////////////
		// normalizing the parameters
		//
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		String fullPath = path+fileName;
		
		logMethod(LOG_DEBUG, "> Entering upload :: path="+path+" fileName="+fileName);
		
		boolean result = false;
		
		/////////////////////////////////////////////
		// checking many thinks before doing the work
		//		
		// checking that the fileName is well formed
		if (!ResourceControl.isWellFormed(fileName)){
			logMethod(LOG_DEBUG, "upload"+" :: fileName="+fileName+"  not well formed");
			throw new BadFormatException();
		}
		// checking that the file does not exist
		else if (exists(fullPath)) {
			logMethod(LOG_DEBUG, "upload"+" :: fullPath="+fullPath+"  already exist");
			throw new StillExistsException();
		}// if (exists(fullPath))
		// checking that the directory where to upload the file exists
		else if (!exists(path)){
			logMethod(LOG_DEBUG, "upload"+" :: path="+path+"  does not exist");
			throw new StillExistsException();
		}// if (!exists(path))
		
		/////////////////////////
		// we can upload the file
		//
		else{
			try {
				logMethod(LOG_DEBUG, "upload"+" :: uploading file "+fileName+" to "+path);
				smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
				SmbFileOutputStream smbFileOutputStream = new SmbFileOutputStream(smbFile);				
				
				byte[] b = new byte[INPUTSTREAM_BUFFER];
				int n;
				while(( n = fileStream.read( b )) > 0 ) {
					smbFileOutputStream.write( b, 0, n );
				}// while(( n = in.read( b )) > 0 )
				
				smbFileOutputStream.close();
				fileStream.close();
				
				logMethod(LOG_DEBUG, "upload"+" :: file "+fileName+" uploaded successfully");
				result = true;
			} catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "upload"+" :: "+e);
				throw new ApplicationException();
			} catch (SmbException e1) {
				logMethod(LOG_ERROR, "upload"+" :: "+e1);
				throw new ApplicationException();
			} catch (UnknownHostException e2) {
				logMethod(LOG_ERROR, "upload"+" :: "+e2);
				throw new ApplicationException();
			} catch (IOException e3) {
				logMethod(LOG_ERROR, "upload"+" :: "+e3);
				throw new ApplicationException();
			}
		}// else (exists(fullPath))
		
		return result;
	}// upload

	
	/**
	 * Delete a resource (file or directory)
	 * @param file resource to delete
	 * @param path path of the resource
	 * @return boolean true if no problem occured else false
	 * @throws ApplicationException
	 * @throws DeleteException
	 * @throws NotAuthorizedDeleteException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean delete(String file, String path) throws ApplicationException, DeleteException, NotAuthorizedDeleteException, NotExistsResourceException, NotAuthorizedException {
		
		logMethod(LOG_DEBUG, "> Entering delete :: path="+path+" file="+file);
		
		//////////////////////////////
		// normalizing the parameters
		//
		file = normalizeResourceUri(file, RESSOURCE_FILEORFOLDER_NAME);
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		
		/////////////
		// variables
		//
		boolean answer = false;
		String fullPath = path+file;
		
		/////////////////////////////////////////////
		// checking many thinks before doing the work
		//	
		// check if the resource exists
		if (! exists(file, path)) {
			logMethod(LOG_DEBUG, "delete"+" :: fullPath="+fullPath+"  does not exist");
			throw new NotExistsResourceException();
		}// if (! exists(file, path))
		else {
			try {
			logMethod(LOG_DEBUG, "delete"+" :: deleting resource "+uri+fullPath);
			smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
			// if the resource to delete is a directory, it must end with '/' - required by the JCIFS API
			if (smbFile.isDirectory()){
				fullPath = normalizeResourceUri(fullPath, RESSOURCE_FOLDER_PATH);
				smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
			}// if (smbFile.isDirectory())
			////////////////////////
			// deleting the resource
			//
			smbFile.delete();
			logMethod(LOG_DEBUG, "delete"+" :: resource "+uri+fullPath+" deleted successfully");
			answer = true;
			} catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "delete"+" :: "+e);
				throw new ApplicationException();
			} catch (SmbException e1) {
				logMethod(LOG_ERROR, "delete"+" :: "+e1);
				throw new ApplicationException();
			}
		}// else (! exists(file, path))
		
		return answer;
	}// delete

	
	/**
	 * Rename a resource (file or directory)
	 * @param oldName resource to rename
	 * @param newName new name of the resource
	 * @param path path of the resource
	 * @return boolean true if no problem occured else false
	 * @throws StillExistsException
	 * @throws BadFormatException
	 * @throws ApplicationException
	 * @throws RenameException
	 * @throws NotAuthorizedRenameException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean rename(String oldName, String newName, String path) throws StillExistsException, BadFormatException, ApplicationException, RenameException, NotAuthorizedRenameException, NotExistsResourceException, NotAuthorizedException, PropertiesException {
		
		logMethod(LOG_DEBUG, "> Entering rename :: oldName="+oldName+" newName="+newName+" path="+path);
		
		boolean answer = false;
		// normalizing the given parameters
		oldName = normalizeResourceUri(oldName, RESSOURCE_FILEORFOLDER_NAME);
		newName = normalizeResourceUri(newName, RESSOURCE_FILEORFOLDER_NAME);
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);

		String oldFullPath = path+oldName;	
		String newFullPath = path+newName;	
		// checking that the resource exists
		if (! exists(oldName, path)) {
			logMethod(LOG_DEBUG, "rename"+" :: oldFullPath="+oldFullPath+"  does not exist");
			throw new NotExistsResourceException();
		}// if (! exists(oldName, path))
		// checking that the new resource name is well formed
		else if (!ResourceControl.isWellFormed(newName)){
			logMethod(LOG_DEBUG, "rename"+" :: newName="+newName+"  not well formed");
    		throw new BadFormatException();
		}// else (!ResourceControl.isWellFormed(newName))
		// checking that the new resource does not already exist
		else if (exists(newName, path)){
			logMethod(LOG_DEBUG, "rename"+" :: newFullPath="+newFullPath+"  already exist");
    		throw new StillExistsException();
		}// else (exists(newName, path))
		else {
			try {
			smbFile = new SmbFile(uri+oldFullPath, ntlmPasswordAuthentication);
			SmbFile newSmbFile = new SmbFile(uri+newFullPath, ntlmPasswordAuthentication);
			logMethod(LOG_DEBUG, "rename"+" :: renaming resource "+oldFullPath+" to "+newFullPath);
			smbFile.renameTo(newSmbFile);
			logMethod(LOG_DEBUG, "rename"+" :: resource "+oldFullPath+" renamed successfully");
			answer = true;
			} catch (SmbException e) {
				logMethod(LOG_ERROR, "rename"+" :: "+e);
				throw new ApplicationException();
			} catch (MalformedURLException e1) {
				logMethod(LOG_ERROR, "rename"+" :: "+e1);
				throw new ApplicationException();
			}
		}// (! exists(oldName, path))
		
		return answer;
		
	}// rename

	
	/**
	 * Create a directory
	 * @param name name of the directory to create
	 * @param path path where to create the directory
	 * @return boolean true if no problem occured else false
	 * @throws ApplicationException
	 * @throws CreateDirectoryException
	 * @throws StillExistsException
	 * @throws BadFormatException
	 * @throws NotAuthorizedNewDirException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean createDir(String name, String path) throws ApplicationException, CreateDirectoryException, StillExistsException, BadFormatException, NotAuthorizedNewDirException, NotExistsResourceException, NotAuthorizedException, PropertiesException {
		
		logMethod(LOG_DEBUG, "> Entering createDir :: name="+name+" path="+path);
		
		//////////////////////////////
		// normalizing the parameters
		//
		name = normalizeResourceUri(name, RESSOURCE_FILEORFOLDER_NAME);
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		
		/////////////
		// variables
		//
		boolean answer = false;
		String fullPath = path+name;			
        
		/////////////////////////////////////////////
		// checking many thinks before doing the work
		//	
		// checking that a resource with the same does not already exists
		boolean exist = exists(fullPath);
        if ( exist ) {
        	logMethod(LOG_DEBUG, "createDir"+" :: fullPath="+fullPath+" already exist");
    		throw new StillExistsException();           	
        }// if ( exist )
        else {
        	// no resource with the same name
        	// checking that the resource name is well formed
        	boolean wellFormed = ResourceControl.isWellFormed(name);
        	if ( !wellFormed ) {
        		logMethod(LOG_DEBUG, "createDir"+" :: name="+name+"  not well formed");
        		throw new BadFormatException();
        	}// if ( !wellFormed )
        	// resource name well formed
        	else {
        		// check that the parent directory exists
        		if (!exists(path)) {
        			logMethod(LOG_DEBUG, "createDir"+" :: path="+path+"  does not exist");
					throw new NotExistsResourceException();
				}// if (!exists(path))
        		else {
        			///////////////////////////////////////////////////////////////////
        			// the parent directory exists, we can finally create the directory
        			//
        			try {
        				logMethod(LOG_DEBUG, "createDir"+" :: creating directory "+uri+fullPath);
        				smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
        				smbFile.mkdir();
        				logMethod(LOG_DEBUG, "createDir"+" :: directory "+uri+fullPath+" created successfully");
						answer = true;
					} catch (SmbException e) {
						logMethod(LOG_ERROR, "createDir"+" :: "+e);
						throw new ApplicationException();
					} catch (MalformedURLException e1) {
						logMethod(LOG_ERROR, "createDir"+" :: "+e1);
						throw new ApplicationException();
					}
        		}// (!exists(path))
        	}// else ( !wellFormed )
        }// else ( exist )
        
		return answer;
	
	}// createDir

	
	/**
	 * Check that we can paste a file in the target directory<br>
	 * <b>This version does not support inter spaces paste !</b>
	 * @param fromSpace the space from which we want to paste - not used
	 * @param toSpaceKey the space key where we want to paste - not used
	 * @param clipboardPath the path of the clipboad
	 * @param clipboard the contain of the clipboard
	 * @param curentDirPath the path of the current dir
	 * @return true if no problem occured else an exception is thrown
	 * @throws ApplicationException
	 * @throws PasteInChildDirectoryException
	 * @throws PasteWithSameNameException
	 * @throws PasteDeletedResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean canPaste(Space fromSpace, String toSpaceKey, String clipboardPath, Vector clipboard, String curentDirPath) throws ApplicationException, PasteInChildDirectoryException, PasteWithSameNameException, PasteDeletedResourceException, NotAuthorizedException {
		
		logMethod(LOG_DEBUG, "> Entering canPaste");
		
		//////////////////////////////
		// normalizing the parameters
		//
		curentDirPath = normalizeResourceUri(curentDirPath, RESSOURCE_FOLDER_PATH);
		
		/////////////////////////////////////////////
		// checking many thinks before doing the work
		//	
		// checking that there is no resource with the same name that the resource we want to paste in the target directory
		logMethod(LOG_DEBUG, "canPaste :: checking that there is no resource with the same name that the resource we want to paste in the target directory");
		Enumeration enum = clipboard.elements();
		while (enum.hasMoreElements()) {
			String resourceName = (String) enum.nextElement();
			String fullPath = curentDirPath+resourceName;
			boolean exist = exists(fullPath);	
			if (exist){
				logMethod(LOG_DEBUG, "canPaste :: the resource "+resourceName+" already exists in the target directory");
				throw new PasteWithSameNameException();	
			}// if (exist)
		}// while (enum.hasMoreElements())
		
		// checking that we do not try to paste a resource in one of its child
		logMethod(LOG_DEBUG, "canPaste :: checking that we do not try to paste a resource in one of its child");
		if (toSpaceKey.equals(fromSpace.getKey())) {
			for (int i=0; i<clipboard.size(); i++) {
				String resourceName = (String)clipboard.elementAt(i);
				if (curentDirPath.startsWith(clipboardPath+resourceName+"/")) {
					logMethod(LOG_DEBUG, "canPaste :: trying to paste the resource in one of its child ("+curentDirPath+")");
					throw new PasteInChildDirectoryException();
				}// if (curentDirPath.startsWith(clipboardPath+resourceName+"/"))
			}// for (int i=0; i<clipboard.size(); i++)
		}// if (toSpaceKey.equals(fromSpace.getKey()))
		
		// checking that no selected resource was deleted
		logMethod(LOG_DEBUG, "canPaste :: checking that no selected resource was deleted");
		ServerAccess fromAccess = fromSpace.getServerAccessObject();
		for (int i=0; i<clipboard.size(); i++) {
			String resourceName = (String)clipboard.elementAt(i);			
			String fullPath = clipboardPath+resourceName;
			boolean exist = fromAccess.exists(fullPath);
           
            if(!fullPath.endsWith(("/")) && !exist) {
            	fullPath=fullPath+"/";
            	exist = exist || fromAccess.exists(fullPath);
            }// if(!fullPath.endsWith(("/")) && !exist)
			
			if (!exist){
				logMethod(LOG_DEBUG, "canPaste :: the selected resource "+fullPath+" was deleted");
				throw new PasteDeletedResourceException();					
			}// if (!exist)
		}// for (int i=0; i<clipboard.size(); i++)
	
		return true;
		
	}// canPaste


	/**
	 * Copy a resource
	 * @param resource resource name
	 * @param fromPath path of the resource
	 * @param toPath path where to copy the resource
	 * @return true if no error occured else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	protected boolean localCopy(String resource, String fromPath, String toPath) throws CopyException, ApplicationException, OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
	
		logMethod(LOG_DEBUG, "> Entering localCopy :: resource="+resource+" fromPath="+fromPath+" toPath="+toPath);
		
		//////////////////////////////
		// normalizing the parameters
		//
		resource = normalizeResourceUri(resource, RESSOURCE_FILEORFOLDER_NAME);
		fromPath = normalizeResourceUri(fromPath, RESSOURCE_FOLDER_PATH);
		toPath = normalizeResourceUri(toPath, RESSOURCE_FOLDER_PATH);
		
		/////////////
		// variables
		//
		boolean result = false;
		String sourceFullPath = fromPath+resource;
		String destinationFullPath = toPath+resource;
		boolean sourceFullPathExist = exists(sourceFullPath);
		boolean destinationDirectoryExist = exists(toPath);
		
		/////////////////////////////////////////////
		// checking many thinks before doing the work
		//	
		// if the resource is a directory it must end with a '/' - required by the SmbFile.copyTo() method
		if (isDirectory(resource, fromPath)) sourceFullPath = normalizeResourceUri(sourceFullPath, RESSOURCE_FOLDER_PATH);
		
		// checking that the source and destination directories are different
		if (fromPath.equals(toPath)) {
			logMethod(LOG_DEBUG, "localCopy"+" :: source and destination directories are the same");
    		throw new CopyException();  
		}// if (fromPath.equals(toPath))
		else if (sourceFullPath.equals(toPath)){
			logMethod(LOG_DEBUG, "localCopy"+" :: can not copy a resource to itself");
    		throw new CopyException();  
		}// 
		// checking that the resource to copy and the destination directory exist
        else if ( !sourceFullPathExist ) {
        	logMethod(LOG_DEBUG, "localCopy"+" :: sourceFullPath="+sourceFullPath+" does not exist");
    		throw new NotExistsResourceException();           	
        }// if ( exist )
		else if( !destinationDirectoryExist ){
			logMethod(LOG_DEBUG, "localCopy"+" :: destinationDirectory="+toPath+" does not exist");
    		throw new NotExistsResourceException();  
		}else{
			try {
				//////////////
				// we can copy
				//
				logMethod(LOG_DEBUG, "localCopy"+" :: copying resource "+resource+" to "+toPath);
				SmbFile destSmbFile = new SmbFile(uri+destinationFullPath, ntlmPasswordAuthentication);
				smbFile = new SmbFile(uri+sourceFullPath, ntlmPasswordAuthentication);
				smbFile.copyTo(destSmbFile);
				logMethod(LOG_DEBUG, "localCopy"+" :: resource="+resource+" copied succesfully");
				result = true;
			} catch (SmbException e) {
				logMethod(LOG_ERROR, "localCopy :: "+e);
	    		throw new NotExistsResourceException();
			} catch (MalformedURLException e1) {
				logMethod(LOG_ERROR, "localCopy :: "+e1);
	    		throw new NotExistsResourceException();
			}
		}//else ( !exist )
		
		return result;
		
	}// localCopy
		
	
	/**
	 * Copy a file from a server to the CIFS server<br>
	 * All required checking (if a directory exists...) are supposed to be done by the calling application
	 * @param fileName name of the file to copy
	 * @param fromAccess space access from which we want to copy
	 * @param absoluteFromPath source path
	 * @param toPath destination path
	 * @return true if no problem occured else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	private boolean distantCopyFile(String fileName, ServerAccess fromAccess, String absoluteFromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		logMethod(LOG_DEBUG, "> Entering distantCopyFile :: absoluteFromPath="+absoluteFromPath+" toPath="+toPath+" fileName="+fileName);
		
		//////////////////////////////
		// normalizing the parameters
		//
		fileName = normalizeResourceUri(fileName, RESSOURCE_FILEORFOLDER_NAME);
		absoluteFromPath = normalizeResourceUri(absoluteFromPath, RESSOURCE_FOLDER_PATH);
		toPath = normalizeResourceUri(toPath, RESSOURCE_FOLDER_PATH);
			
		/////////////
		// variables
		//
		String absoluteToPath = toPath+fileName;			
		InputStream streamFromFile;
		boolean result = false;
		
		try {
			// getting the stream of the file to copy
			streamFromFile = fromAccess.getMethodData(absoluteFromPath);
			if (streamFromFile==null) {
				logMethod(LOG_DEBUG, "distantCopyFile :: stream for absoluteFromPath "+absoluteFromPath+" is null");
				throw new NotExistsResourceException();
			}// if (streamFromFile==null)
			else {
				smbFile = new SmbFile(uri+absoluteToPath, ntlmPasswordAuthentication);
				SmbFileOutputStream smbFileOutputStream = new SmbFileOutputStream(smbFile);
				
				logMethod(LOG_DEBUG, "distantCopyFile"+" :: copying file "+fileName+" to "+toPath);
				byte[] b = new byte[INPUTSTREAM_BUFFER];
				int n;
				while(( n = streamFromFile.read( b )) > 0 ) {
					smbFileOutputStream.write( b, 0, n );
				}// while(( n = in.read( b )) > 0 )
				logMethod(LOG_DEBUG, "distantCopyFile"+" :: file="+fileName+" copied succesfully");
				
				smbFileOutputStream.close();
				streamFromFile.close();
				result = true;
				
			}// else (streamFromFile==null)
		} catch (IOException e){
			logMethod(LOG_ERROR, "distantCopyFile :: "+e);
    		throw new ApplicationException();
		}
				
		return result;
		
	}// distantCopyFile
	
	
	/**
	 * Copy a directory from a server to the CIFS server<br>
	 * All required checking (if a directory exists...) are supposed to be done by the calling application
	 * @param directoryName name of the directory to copy
	 * @param fromAccess space access from which we want to copy
	 * @param absoluteFromPath source path
	 * @param toPath destination path
	 * @return true if no problem occured else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 * @throws ServerException
	 */
	private boolean distantCopyDirectory(String directoryName, ServerAccess fromAccess, String absoluteFromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException {
		
		logMethod(LOG_DEBUG, "> Entering distantCopyDirectory :: directoryName="+directoryName+" absoluteFromPath="+absoluteFromPath+" toPath="+toPath);
		
		//////////////////////////////
		// normalizing the parameters
		//
		directoryName = normalizeResourceUri(directoryName, RESSOURCE_FILEORFOLDER_NAME);
		absoluteFromPath = normalizeResourceUri(absoluteFromPath, RESSOURCE_FOLDER_PATH);
		toPath = normalizeResourceUri(toPath, RESSOURCE_FOLDER_PATH);
			
		/////////////
		// variables
		//
		String absoluteToPath = toPath+directoryName;			
		boolean result = false;
		
		if (fromAccess.exists(absoluteFromPath)) {
			
			try {
				// create this directory on the new server
				logMethod(LOG_DEBUG, "distantCopyDirectory"+" :: creating directory "+absoluteToPath);
				smbFile = new SmbFile(uri+absoluteToPath, ntlmPasswordAuthentication);
				smbFile.mkdir();
				logMethod(LOG_DEBUG, "distantCopyDirectory"+" :: directory "+absoluteToPath+" created successfully");
			} catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "distantCopyDirectory :: "+e);
				throw new ApplicationException();
			} catch (SmbException e1) {
				logMethod(LOG_ERROR, "distantCopyDirectory :: "+e1);
				throw new ApplicationException();
			}
			
			// list the resources into this directory				
			ChannelResource[] resources = fromAccess.ls(absoluteFromPath);
			
			// for each resource, we copy
			for (int i=0; i<resources.length; i++) {
				distantCopy(resources[i], fromAccess, absoluteToPath);
			}// for (int i=0; i<resources.length; i++)

			result = true;
			
		}// if (fromAccess.exists(absoluteFromPath))
		
		return result;
		
	}// distantCopyDirectory
	
	
	/**
	 * Copy a resource from a server to the CIFS server<br>
	 * All required checking (if a directory exists...) are supposed to be done by the calling application
	 * @param resource name of the resource to copy
	 * @param fromAccess space access from which we want to copy
	 * @param toPath destination path
	 * @return true if no problem occured else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 * @throws ServerException
	 */
	protected boolean distantCopy(String resource, ServerAccess fromAccess, String fromPath, String toPath) throws CopyException, ApplicationException,OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException {
		
		logMethod(LOG_DEBUG, "> Entering distantCopy :: fromPath="+fromPath+" toPath="+toPath+" resource="+resource);
		
		//////////////////////////////
		// normalizing the parameters
		//
		fromPath = normalizeResourceUri(fromPath, RESSOURCE_FOLDER_PATH);
		toPath = normalizeResourceUri(toPath, RESSOURCE_FOLDER_PATH);
		resource = normalizeResourceUri(resource, RESSOURCE_FILEORFOLDER_NAME);
		
		// checking if the resource is a directory   
		boolean isDirectory = fromAccess.isDirectory(resource, fromPath);	
				
		// if file
		if (!isDirectory) {
			String absoluteFromPath = normalizeResourceUri(fromPath+resource, RESSOURCE_FILE_PATH);
			return distantCopyFile(resource, fromAccess, absoluteFromPath, toPath);
		}// if (!isDirectory)
		// if directory
		else {
			String absoluteFromPath = normalizeResourceUri(fromPath+resource, RESSOURCE_FOLDER_PATH);
			return distantCopyDirectory(resource, fromAccess, absoluteFromPath, toPath);
		}// else (!isDirectory)

	}// distantCopy
	
	
	/**
	 * Copy a resource from a server to the CIFS server<br>
	 * All required checking (if a directory exists...) are supposed to be done by the calling application
	 * @param resource ChannelResource to copy
	 * @param fromAccess space access from which we want to copy
	 * @param toPath destination path
	 * @return true if no problem occured else false
	 * @throws CopyException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 * @throws ServerException
	 */
	private boolean distantCopy(ChannelResource resource, ServerAccess fromAccess, String toPath) throws CopyException, ApplicationException,OverQuotaException, PasteNotAuthorizedResourceException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException, ServerException {
		
		logMethod(LOG_DEBUG, "> Entering distantCopy :: toPath="+toPath+" resource="+resource);
		
		//////////////////////////////
		// normalizing the parameters
		//
		toPath = normalizeResourceUri(toPath, RESSOURCE_FOLDER_PATH);
		
		// check if resource is a directory   
		boolean isDirectory = resource.isCollection(); 	
		
		String name = normalizeResourceUri(resource.getDisplayName(), RESSOURCE_FILEORFOLDER_NAME);
		String path = normalizeResourceUri(resource.getPath(), RESSOURCE_FOLDER_PATH);
		String absoluteFromPath =  normalizeResourceUri(resource.getPath(), RESSOURCE_FOLDER_PATH);
		
		// if directory
		if (!isDirectory) {
			return distantCopyFile(name, fromAccess, absoluteFromPath, toPath);
		}// if (!isDirectory)
		// if file
		else {
			return distantCopyDirectory(name, fromAccess, absoluteFromPath, toPath);
		}// else (!isDirectory)
		
	}// distantCopy

	
	/**
	 * Move a resource
	 * @param resource resource name
	 * @param fromPath path of the resource
	 * @param toPath path where to copy the resource
	 * @return true if no error occured else false
	 * @throws MoveException
	 * @throws ApplicationException
	 * @throws OverQuotaException
	 * @throws NotExistsResourceException
	 * @throws PasteNotAuthorizedResourceException
	 * @throws NotAuthorizedException
	 * @throws NotAuthorizedUploadException
	 */
	protected boolean localMove(String resource, String fromPath, String toPath) throws MoveException, ApplicationException,OverQuotaException, NotExistsResourceException, PasteNotAuthorizedResourceException, NotAuthorizedException, NotAuthorizedUploadException {
		
		logMethod(LOG_DEBUG, "> Entering localMove :: resource="+resource+" fromPath="+fromPath+" toPath="+toPath);
		
		//////////////////////////////
		// normalizing the parameters
		//
		resource = normalizeResourceUri(resource, RESSOURCE_FILEORFOLDER_NAME);
		fromPath = normalizeResourceUri(fromPath, RESSOURCE_FOLDER_PATH);
		toPath = normalizeResourceUri(toPath, RESSOURCE_FOLDER_PATH);
					
		/////////////
		// variables
		//
		boolean result = false;
		String sourceFullPath = fromPath+resource;
		String destinationFullPath = toPath+resource;
		boolean sourceFullPathExist = exists(sourceFullPath);
		boolean destinationFullPathExist = exists(destinationFullPath);
		boolean destinationDirectoryExist = exists(toPath);
		
		// if the resource is a directory it must end with a '/' - required by the SmbFile.copyTo() method
		if (isDirectory(resource, fromPath)) sourceFullPath = normalizeResourceUri(sourceFullPath, RESSOURCE_FOLDER_PATH);
		
		/////////////////////////////////////////////
		// checking many thinks before doing the work
		//	
		// checking that the source and destination directories are different
		if (fromPath.equals(toPath)) {
			logMethod(LOG_DEBUG, "localMove"+" :: source and destination directories are the same");
    		throw new MoveException();  
		}// if (fromPath.equals(toPath))
		else if (sourceFullPath.equals(toPath)){
			logMethod(LOG_DEBUG, "localCopy"+" :: can not copy a resource to itself");
    		throw new MoveException();  
		}// if (sourceFullPath.equals(toPath))
		// checking that the resource to copy and the destination directory exist
        else if ( !sourceFullPathExist ) {
        	logMethod(LOG_DEBUG, "localMove"+" :: sourceFullPath="+sourceFullPath+" does not exist");
    		throw new NotExistsResourceException();           	
        }// if ( !sourceFullPathExist )
		else if( !destinationDirectoryExist ){
			logMethod(LOG_DEBUG, "localMove"+" :: destinationDirectory="+toPath+" does not exist");
    		throw new NotExistsResourceException();  
		}// if( !destinationDirectoryExist )
		else{
			try {
				//////////////
				// we can move
				//
				logMethod(LOG_DEBUG, "localMove"+" :: moving resource "+resource+" to "+toPath);
				SmbFile destSmbFile = new SmbFile(uri+destinationFullPath, ntlmPasswordAuthentication);
				smbFile = new SmbFile(uri+sourceFullPath, ntlmPasswordAuthentication);
				smbFile.copyTo(destSmbFile);
				smbFile.delete();
				logMethod(LOG_DEBUG, "localMove"+" :: resource="+resource+" moved succesfully");
				result = true;
			} catch (SmbException e) {
				logMethod(LOG_ERROR, "localMove :: "+e);
	    		throw new NotExistsResourceException();
			} catch (MalformedURLException e1) {
				logMethod(LOG_ERROR, "localMove :: "+e1);
	    		throw new NotExistsResourceException();
			}
		}//else ( !exist )
		
		return result;
		
	}// localMove
	
	
	/**
	 * Download a file
	 * @param name the file name
	 * @param path the path of the file
	 * @return the ChannelWebdavResource
	 * @throws DownloadException
	 */
	public ChannelResource download(String name, String path) throws DownloadException {
		
		logMethod(LOG_DEBUG, "> Entering download :: name="+name+" path="+path);
		
		//////////////////////////////
		// normalizing the parameters
		//
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		name = normalizeResourceUri(name, RESSOURCE_FILEORFOLDER_NAME);
		
		/////////////
		// variables
		//
		String fullPath = path+name;
		ChannelResource result = null;
		
		boolean exist;
		try {
			exist = exists(fullPath);
		} catch (ApplicationException e) {
			logMethod(LOG_ERROR, "download"+" :: "+e);
			throw new DownloadException();
		} catch (NotAuthorizedException e1) {
			logMethod(LOG_ERROR, "download"+" :: "+e1);
			throw new DownloadException();
		}
		
		// checking that the file to download exists
		if (!exist) {
			logMethod(LOG_DEBUG, "download"+" :: fullPath="+fullPath+"  does not exist");
			throw new DownloadException();
		}// if (exists(fullPath))
				
		try {
			smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
			
			// gathering information to build the result
			String displayName = smbFile.getName();
			logMethod(LOG_DEBUG, "download"+" :: gathering information for "+displayName);
			String resourcePath = smbFile.getPath();
			int contentLength = smbFile.getContentLength();
			long lastModified = smbFile.getLastModified();
			boolean isCollection = smbFile.isDirectory();
			String contentType =  URLConnection.guessContentTypeFromName(displayName);
			InputStream inputStream;
			if (!isCollection){
				inputStream = smbFile.getInputStream();
			}// if (!isCollection)
			else{
				inputStream = null;
			}// else (!isCollection)
			
			// the getPath() method return the full path like smb://myServer/myDirectory/myFile.txt
			// we only want to return something like /myDirectory/myFile.txt
			resourcePath = resourcePath.substring(uri.length());
			
			logMethod(LOG_DEBUG, "download"+" :: downloading "+displayName);
			result = new ChannelResource(displayName, resourcePath, contentLength, contentType, lastModified, isCollection, inputStream);
			logMethod(LOG_DEBUG, "download"+" :: file "+displayName+" downloaded successfully");
		} catch (SmbException e) {
			logMethod(LOG_ERROR, "download"+" :: "+e);
			throw new DownloadException();
		} catch (IOException e1) {
			logMethod(LOG_ERROR, "download"+" :: "+e1);
			throw new DownloadException();
		}
		
		return result;
		
	}// download

	
	/**
	 * Return the stream of a file
	 * @param fullPath the full path of the file
	 * @return the InputStream
	 * @throws IOException
	 */
	public InputStream getMethodData(String fullPath) throws IOException {
		
		logMethod(LOG_DEBUG, "> Entering getMethodData :: fullPath="+fullPath);
		
		// normalizing the given parameters
		fullPath = normalizeResourceUri(fullPath, RESSOURCE_FILE_PATH);
		
		InputStream result = null;
		boolean exist;
		
		try {
			exist = exists(fullPath);
		} catch (ApplicationException e) {
			logMethod(LOG_ERROR, "getMethodData"+" :: "+e);
			throw new IOException();
		} catch (NotAuthorizedException e1) {
			logMethod(LOG_ERROR, "getMethodData"+" :: "+e1);
			throw new IOException();
		}
		
		// checking that the file to download exists
		if (!exist) {
			logMethod(LOG_DEBUG, "getMethodData"+" :: fullPath="+fullPath+"  does not exist");
			throw new IOException();
		}// if (exists(fullPath))
				
		smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
		
		// checking that the file to download is not a directory
		if (smbFile.isDirectory()) {
			logMethod(LOG_DEBUG, "getMethodData"+" :: fullPath="+fullPath+"  is a directory");
			throw new IOException();
		}// if (exists(fullPath))
		
		result = smbFile.getInputStream();
		
		return result;
		
	}// getMethodData

	
	/**
	 * Check is the resource (file or directory) exists
	 * @param fullPath the full path of the resource
	 * @return true if the resource exists else false
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */
	public boolean exists(String fullPath) throws ApplicationException, NotAuthorizedException {
		
		logMethod(LOG_DEBUG, "> Entering exists"+" :: fullPath="+fullPath);
		
		boolean result;
		// normalizing the given parameters
		fullPath = normalizeResourceUri(fullPath, RESSOURCE_UNKNOWN_PATH);
		
		logMethod(LOG_DEBUG, "exists"+" :: "+fullPath);
		try {
			smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
			result = smbFile.exists();
			logMethod(LOG_DEBUG, "exists"+" :: result="+result);
			return result;
		} catch (MalformedURLException e) {
			logMethod(LOG_ERROR, "exists"+" :: "+e);
            throw new ApplicationException();
		} catch (SmbException e1) {
			logMethod(LOG_ERROR, "exists"+" :: "+e1);
            throw new ApplicationException();
		}
		
	}// exists

	
	/**
	 * Check is the resource (file or directory) exists
	 * @param resourceName the name of the resource
	 * @param path the relative path of the resource
	 * @return true if the resource exists else false
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 */
	public boolean exists(String resourceName, String path) throws ApplicationException, NotAuthorizedException {
		
		logMethod(LOG_DEBUG, "> Entering exists"+" :: path="+path+" resourceName="+resourceName);
		
		boolean result;
		// normalizing the given parameters
		resourceName = normalizeResourceUri(resourceName, RESSOURCE_FILEORFOLDER_NAME);
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		
		// calling the exist(fullPath) method
		logMethod(LOG_DEBUG, "exists"+" :: path="+path+" ressourceName="+resourceName);
		String pathAndName = path+resourceName;			
		result = exists(pathAndName);
		logMethod(LOG_DEBUG, "exists"+" :: result="+result);
		return result;
		
	}// exists

	
	/**
	 * Check if we are authorized to read this resource (file or directory)
	 * @param resourceName the name of the resource
	 * @param path relative path of the resource
	 * @return true if authorized else false
	 * @throws ApplicationException
	 */
	public boolean canRead(String resourceName, String path) throws ApplicationException {
		
		logMethod(LOG_DEBUG, "> Entering canRead"+" :: path="+path+" resourceName="+resourceName);
		
		// normalizing the given parameters
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		resourceName = normalizeResourceUri(resourceName, RESSOURCE_FILEORFOLDER_NAME);
		
		String fullPath = path+resourceName;
		boolean canRead;
		boolean exist = false;
		try {
			exist = exists(fullPath);
		} catch (ApplicationException e) {
			logMethod(LOG_ERROR, "canRead"+" :: "+e);
			throw new ApplicationException();
		} catch (NotAuthorizedException e1) {
			logMethod(LOG_ERROR, "canRead"+" :: "+e1);
			canRead = false;
		}
		
		// checking that the resource exists
		if ( !exist ) {
			logMethod(LOG_DEBUG, "canRead"+" :: fullPath="+fullPath+" does not exist");
			return false;
		}// if ( exist )
		else {
			return canRead(fullPath);	
		}// else ( exist )
		
	}// canRead

	
	/**
	 * Check if we are authorized to read this resource (file or directory)
	 * @param path full path of the resource
	 * @return true if authorized else false
	 * @throws ApplicationException
	 */
	public boolean canRead(String path) throws ApplicationException {
		
		logMethod(LOG_DEBUG, "> Entering canRead"+" :: path="+path);
		
		// normalizing the given parameters
		path = normalizeResourceUri(path, RESSOURCE_UNKNOWN_PATH);
		
		boolean canRead = false;
        boolean exist;
		try {
			exist = exists(path);
		} catch (ApplicationException e) {
			logMethod(LOG_ERROR, "canRead"+" :: "+e);
			throw new ApplicationException();
		} catch (NotAuthorizedException e1) {
			logMethod(LOG_ERROR, "canRead"+" :: "+e1);
			throw new ApplicationException();
		}
		
		// checking that the resource exists
        if ( !exist ) {
        	logMethod(LOG_DEBUG, "canRead"+" :: path="+path+" does not exist");
        	canRead = false;  // just for comprehension
        }// if ( exist )
        else {
	        try {
				smbFile = new SmbFile(uri+path, ntlmPasswordAuthentication);
				canRead = smbFile.canRead();
	        } catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "canRead"+" :: "+e);
	            throw new ApplicationException();
			} catch (SmbException e) {
				logMethod(LOG_ERROR, "canRead"+" :: "+e);
	            throw new ApplicationException();
			}
        }// else ( !exist )
        
		return canRead;
		
	}// canRead
	

	/**
	 * Check that the resource is a directory
	 * @param name the name of the resource
	 * @param path the relative path of the resource
	 * @return true if the resource is a directory, false else
	 * @throws ApplicationException
	 * @throws NotAuthorizedException
	 * @throws NotExistsResourceException
	 */
	public boolean isDirectory(String name, String path) throws ApplicationException, NotAuthorizedException, NotExistsResourceException {
		
		logMethod(LOG_DEBUG, "> Entering isDirectory"+" :: path="+path+" name="+name);
		
		// normalizing the given parameters
		name = normalizeResourceUri(name, RESSOURCE_FILEORFOLDER_NAME);
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
				
		String fullPath = path+name;			
        boolean exist = exists(fullPath);
        boolean isDirectory = false;
        
        // checking that the resource exists
        if ( !exist ) {
        	logMethod(LOG_DEBUG, "isDirectory"+" :: fullPath="+fullPath+" does not exist");
    		throw new NotExistsResourceException();           	
        }// if ( exist )
		else{
			try {
				smbFile = new SmbFile(uri+path+name, ntlmPasswordAuthentication);
				isDirectory = smbFile.isDirectory();
			} catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "isDirectory"+" :: "+e);
				throw new ApplicationException();
			} catch (SmbException e1) {
				logMethod(LOG_ERROR, "isDirectory"+" :: "+e1);
				throw new ApplicationException();
			}
		}// else ( !exist )
		return isDirectory;
		
	}// isDirectory

	
	/**
	 * Check that the directory is empty
	 * @param dir the name of the directory
	 * @param path the relative path of the directory
	 * @return true if the directory is empty, else false
	 * @throws ApplicationException
	 * @throws NotExistsResourceException
	 * @throws NotAuthorizedException
	 */
	public boolean isEmpty(String dir, String path) throws ApplicationException, NotExistsResourceException, NotAuthorizedException {
		
		logMethod(LOG_DEBUG, "> Entering isEmpty"+" :: path="+path+" dir="+dir);
		
		// normalizing the given parameters
		dir = normalizeResourceUri(dir, RESSOURCE_FILEORFOLDER_NAME);
		path = normalizeResourceUri(path, RESSOURCE_FOLDER_PATH);
		String fullPath = path+dir;	
		// full path is a directory and must end with '/' - required by the JCIFS API
		fullPath = normalizeResourceUri(fullPath, RESSOURCE_FOLDER_PATH);
		boolean isEmpty = false;		
        boolean exist = exists(fullPath);
                
		// checking that the resource exists
        if ( !exist ) {
        	logMethod(LOG_DEBUG, "isEmpty"+" :: fullPath="+fullPath+" does not exist");
    		throw new NotExistsResourceException();           	
        }// if ( exist )
		else {
			try {
				smbFile = new SmbFile(uri+fullPath, ntlmPasswordAuthentication);
				isEmpty = (smbFile.listFiles().length == 0);
			} catch (MalformedURLException e) {
				logMethod(LOG_ERROR, "isEmpty"+" :: "+e);
				throw new ApplicationException();
			} catch (SmbException e) {
				logMethod(LOG_ERROR, "isEmpty"+" :: "+e);
				throw new ApplicationException();
			}
		}// else ( !exist )
        
		return isEmpty;
		
	}// isEmpty


	/**
	 * not implemented
	 */
	public String getProperty(String namespace, String path, String propertyName) throws ServerException {
		return null;
	}// getProperty

	/**
	 * not implemented
	 */
	public boolean setProperty(String namespace, String path, String propertyName, String propertyValue) throws ServerException {
		return false;
	}// setProperty

	/**
	 * not implemented
	 */
	public EsupPermissions getPermissions(String path, String permissionType) throws AclReadException, AclAccessException, NotSupportedAclException {
		throw new NotSupportedAclException();
	}// getPermissions

	/**
	 * not implemented
	 */
	public EsupPermissions getPermissions(String path) throws AclReadException, AclAccessException, NotSupportedAclException {
		throw new NotSupportedAclException();
	}// getPermissions

	/**
	 * not implemented
	 */
	public EsupPermissions grant(String path, String principal, String permissionType) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {
		return null;
	}// grant

	/**
	 * not implemented
	 */
	public EsupPermissions deny(String path, String principal, String permissionType) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {
		return null;
	}// deny

	/**
	 * not implemented
	 */
	public EsupPermissions revoke(String path, String principal, String permissionType) throws AclReadException, AclAccessException, AclWriteException, NotSupportedAclException {
		return null;
	}// revoke

	/**
	 * not implemented
	 */
	public Vector hasInheritedPermission(String path, String principal, String permissionType, boolean negative) throws AclReadException, AclAccessException, NotSupportedAclException {
		return null;
	}// hasInheritedPermission

	/**
	 * not implemented
	 */
	public boolean hasNotInheritedPermission(String path, String principal, String permissionType, boolean negative) throws AclReadException, AclAccessException, NotSupportedAclException {
		return false;
	}// hasNotInheritedPermission

	
}// CIFSAccessImpl
