org.apache.webdav.cmd.Client.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.webdav.cmd.Client.java

Source

/*
 * $Header$
 * $Revision: 208205 $
 * $Date: 2004-11-27 07:38:49 +0800 (Sat, 27 Nov 2004) $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.apache.webdav.cmd;

import antlr.RecognitionException;
import antlr.TokenStreamException;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.HttpsURL;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.webdav.lib.Ace;
import org.apache.webdav.lib.Lock;
import org.apache.webdav.lib.Privilege;
import org.apache.webdav.lib.Property;
import org.apache.webdav.lib.PropertyName;
import org.apache.webdav.lib.ResponseEntity;
import org.apache.webdav.lib.WebdavResource;
import org.apache.webdav.lib.methods.DepthSupport;
import org.apache.webdav.lib.methods.LockMethod;
import org.apache.webdav.lib.properties.AclProperty;
import org.apache.webdav.lib.properties.LockDiscoveryProperty;
import org.apache.webdav.lib.properties.PrincipalCollectionSetProperty;
import org.apache.webdav.lib.properties.ResourceTypeProperty;
import org.apache.webdav.lib.util.QName;

/**
 * The Slide client, the command line version for WebDAV client.
 *
 */
final class Client {

    private Spool spool;
    private InputStream in;
    private PrintStream out;
    private boolean displayPrompt = true;

    /** The path for the display information. */
    private String path = "";

    /** The command prompt for the display information. */
    private String commandPrompt = null;

    /** The http URL on the client connection. */
    private HttpURL httpURL;

    /** The debug level. */
    private int debugLevel = DEBUG_OFF;

    /** The WebDAV resource. */
    private WebdavResource webdavResource = null;

    /** The current path on the local system. */
    private File dir = new File(".");

    /////////////////////////////////////////////////////////////////

    Client(InputStream in, PrintStream out) {
        this.spool = new Spool(in, out);
        this.in = in;
        this.out = new PrintStream(spool.getOutputStream());
        updatePrompt(getPath());
    }

    void run() {
        while (true) {
            try {
                InputStream in = spool.getInputStream();
                ClientLexer lexer = new ClientLexer(new DataInputStream(in));
                ClientParser parser = new ClientParser(lexer);
                parser.setClient(this);
                parser.commands();
            } catch (TokenStreamException ex) {
                handleException(ex);
            } catch (RecognitionException ex) {
                handleException(ex);
            }
        }
        // TODO test EOF  ???
    }

    ///////////////////////////////////////////////////////////////////
    // Helper funtions for the parser and error handlers
    ///////////////////////////////////////////////////////////////////

    void printInvalidCommand(String command) {
        out.println("Error: invalid command: " + command);
    }

    void printUsage(String command) {
        out.println("Syntax error. \"help\" for more info");
        //        out.println("Usage: " + command + " ...");
        //        out.println
        //            ("[Help] open " +
        //             "http://hostname[:port][/path]");
        //        out.println("Syntax: grant <namespace> <permission> on <path> to <principal>");
        //        out.println("Syntax: revoke <namespace> <permission> on <path> from <principal>");
        //        out.println("Syntax: deny <namespace> <permission> on <path> to <principal>");
        //        out.println("Syntax: lock <path>");
        //        out.println("Syntax: unlock <path>");
        //    out.println("Syntax: vc/VersionControl <path>");
        //        else out.println("Syntax: eReport path");
        //        else out.println("Syntax: lReport <property> \n History URLs are needed");

    }

    void prompt() {
        if (displayPrompt)
            out.print(getPrompt());
    }

    void print(String line) {
        out.println(line);
    }

    private void handleException(Exception ex) {
        if (ex instanceof HttpException) {
            if (((HttpException) ex).getReasonCode() == HttpStatus.SC_METHOD_NOT_ALLOWED) {
                out.println("Warning: Not WebDAV-enabled?");
            } else if (((HttpException) ex).getReasonCode() == HttpStatus.SC_UNAUTHORIZED) {
                out.println("Warning: Unauthorized");
            } else {
                out.println("Warning: " + ex.getMessage());
            }
        } else if (ex instanceof IOException) {
            out.println("Error: " + ex.getMessage());
        } else {
            out.println("Fatal Error: " + ex.getMessage());
            ex.printStackTrace(out);
            out.println("Please, email to slide-user@jakarta.apache.org");
            System.exit(-1);
        }
    }

    /////////////////////////////////////////////////////////////////
    // Commands available on the command line
    /////////////////////////////////////////////////////////////////

    void setEchoEnabled(boolean isEnabled) {
        spool.setEcho(isEnabled);
        setDisplayPrompt(isEnabled);

        // if this is an interactive client keep the prompt
        if (this.in == System.in)
            setDisplayPrompt(true);
    }

    void executeScript(String scriptname) {
        try {
            FileInputStream script = new FileInputStream(scriptname);
            Client scriptClient = new Client(script, out);
            scriptClient.setDisplayPrompt(false);
            out.println("Executing script: " + scriptname);
            scriptClient.run();
            out.println("Script " + scriptname + " complete.");
            script.close();
        } catch (FileNotFoundException ex) {
            out.println("Error: Script " + scriptname + " not found.");
        } catch (IOException ex) {
            out.println("Error: " + ex.toString() + " during execution of " + scriptname);
        }
    }

    void enableSpoolToFile(String filename) {
        out.println("Spool to file: " + filename);
        try {
            spool.enable(filename);
        } catch (FileNotFoundException ex) {
            out.println("Error: Could not spool to file: " + filename);
            disableSpoolToFile();
        }
    }

    void disableSpoolToFile() {
        spool.disable();
        out.println("Spooling disabled");
    }

    /** Debug level for all debug messages */
    final static int DEBUG_ON = Integer.MAX_VALUE;

    /** Debug level for no debug messages */
    final static int DEBUG_OFF = 0;

    /**
     * Set the debug level
     */
    void setDebug(int level) {
        this.debugLevel = level;
        if (webdavResource != null)
            webdavResource.setDebug(debugLevel);

        switch (level) {
        case DEBUG_ON:
            out.println("The debug flag is on.");
            break;
        case DEBUG_OFF:
            out.println("The debug flag is off.");
            break;
        default:
            out.println("The debug level is " + level);
            break;
        }
    }

    void connect(String uri) {

        if (!uri.endsWith("/") && !uri.endsWith("\\")) {
            // append / to the path
            uri += "/";
        }

        out.println("connect " + uri);

        try {
            // Set up for processing WebDAV resources
            httpURL = uriToHttpURL(uri);
            if (webdavResource == null) {
                webdavResource = new WebdavResource(httpURL);
                webdavResource.setDebug(debugLevel);

                // is not a collection?
                if (!((ResourceTypeProperty) webdavResource.getResourceType()).isCollection()) {
                    webdavResource = null;
                    httpURL = null;
                    out.println("Error: " + uri + " is not a collection! Use open/connect only for collections!");
                }

            } else {
                webdavResource.close();
                webdavResource.setHttpURL(httpURL);
            }
            setPath(webdavResource.getPath());
        } catch (HttpException we) {
            out.print("HttpException.getReasonCode(): " + we.getReasonCode());
            if (we.getReasonCode() == HttpStatus.SC_UNAUTHORIZED) {
                try {
                    out.print("UserName: ");
                    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                    String userName = in.readLine();
                    if ((userName == null) || (userName.length() == 0)) {
                        disconnect();
                        return;
                    }
                    userName = userName.trim();
                    System.out.print("Password: ");
                    String password = in.readLine();
                    if (password != null)
                        password = password.trim();
                    try {
                        if (webdavResource != null)
                            webdavResource.close();
                    } catch (IOException e) {
                    } finally {
                        httpURL = null;
                        webdavResource = null;
                    }
                    httpURL = uriToHttpURL(uri);
                    // It should be used like this way.
                    httpURL.setUserinfo(userName, password);
                    webdavResource = new WebdavResource(httpURL);
                    webdavResource.setDebug(debugLevel);
                    setPath(webdavResource.getPath());

                    if (!((ResourceTypeProperty) webdavResource.getResourceType()).isCollection()) {
                        webdavResource = null;
                        httpURL = null;
                        out.println(
                                "Error: " + uri + " is not a collection! Use open/connect only for collections!");
                    }
                } catch (Exception ex) {
                    handleException(ex);
                    httpURL = null;
                    webdavResource = null;
                }
            } else {
                handleException(we);
                httpURL = null;
                webdavResource = null;
            }
        } catch (Exception ex) {
            handleException(ex);
            webdavResource = null;
            httpURL = null;
        }
        updatePrompt(getPath());
    }

    void disconnect() {
        out.println("disconnect");
        try {
            webdavResource.close();
        } catch (IOException e) {
        } finally {
            // Make sure the connection closed.
            httpURL = null;
            webdavResource = null;
        }
        updatePrompt(getPath());
    }

    void options(String path) {
        out.println("options " + path);

        String param = path;
        try {
            boolean succeeded = false;
            if (param != null) {
                if (!param.startsWith("/")) {
                    httpURL = uriToHttpURL(param);
                    Enumeration opts = null;
                    try {
                        // OPTIONS business logic
                        opts = webdavResource.optionsMethod(httpURL);
                        while (opts.hasMoreElements()) {
                            out.print(opts.nextElement());
                            if (opts.hasMoreElements()) {
                                out.print(", ");
                            } else {
                                out.println();
                            }
                        }
                    } catch (HttpException we) {
                        if (we.getReasonCode() == HttpStatus.SC_UNAUTHORIZED) {
                            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                            out.print("UserName: ");
                            String userName = in.readLine();
                            if (userName != null && userName.length() > 0) {
                                userName = userName.trim();
                                out.print("Password: ");
                                String password = in.readLine();
                                if (password != null)
                                    password = password.trim();
                                try {
                                    // OPTIONS business logic
                                    httpURL.setUserinfo(userName, password);
                                    opts = webdavResource.optionsMethod(httpURL);
                                    while (opts.hasMoreElements()) {
                                        out.print(opts.nextElement());
                                        if (opts.hasMoreElements()) {
                                            out.print(", ");
                                        } else {
                                            out.println();
                                        }
                                    }
                                } catch (Exception e) {
                                    out.println("Error: " + e.getMessage());
                                }
                            }
                        } else {
                            out.println("Error: " + we.getMessage());
                        }
                    } catch (IOException e) {
                        out.println("Error: Check! " + e.getMessage());
                    }
                    httpURL = null;
                    return;
                } else if (webdavResource != null) {
                    succeeded = webdavResource.optionsMethod(param);
                } else {
                    out.println("Not connected yet.");
                }
            } else if (webdavResource != null) {
                succeeded = webdavResource.optionsMethod("*");
            } else {
                out.println("Not connected yet.");
            }

            if (succeeded) {
                out.print("Allowed methods by http OPTIONS: ");
                Enumeration allowed = webdavResource.getAllowedMethods();
                while (allowed.hasMoreElements()) {
                    out.print(allowed.nextElement());
                    if (allowed.hasMoreElements())
                        out.print(", ");
                }
                Enumeration davCapabilities = webdavResource.getDavCapabilities();
                if (davCapabilities.hasMoreElements())
                    out.print("\nDAV: ");
                while (davCapabilities.hasMoreElements()) {
                    out.print(davCapabilities.nextElement());
                    if (davCapabilities.hasMoreElements())
                        out.print(", ");
                }
                out.println();
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void help(String topic) {
        if (topic == null) {
            printSlideClientUsage();
        } else {
            out.println("No help available on " + topic);
        }
    }

    void lpwd() {
        try {
            out.println(dir.getCanonicalPath());
        } catch (IOException ex) {
            out.println("Warning: Not found the path");
        }
    }

    private File getFileByPath(String path) {

        if (path != null) {
            // set a new file if '\' or '/' at the begin of path 
            // or ':' at the 2nd position of path exists.
            // if not: take the old parent entry of file and add a '/' to path.
            return (path.startsWith("/") || path.startsWith("\\")
                    || ((path.length() > 1) && (path.charAt(1) == ':'))) ? new File(path)
                            : new File(dir, "/" + path);
        } else {
            return dir;
        }

    }

    void lcd(String path) {
        File anotherDir = getFileByPath(path);

        if (anotherDir.isDirectory()) {
            dir = anotherDir;
        } else {
            out.println("Warning: path not found!");
        }

        updatePrompt(getPath());

    }

    void lls(String options, String path) {
        // set default option.
        char option = 'F';
        if ((options != null) && (options.indexOf('l') > 0))
            option = 'l';

        File temp = getFileByPath(path);

        if (!temp.exists() || !temp.isDirectory()) {
            out.println("Warning: path not found!");
            return;
        }

        String[] list = temp.list();
        // TODO: consider of options like '-a' for all and so on.
        switch (option) {
        case 'l':
            for (int i = 0; i < list.length; i++) {
                String s = list[i];
                File file = new File(temp, s);
                for (int j = 0; j < 4; j++) {
                    switch (j) {
                    case 0:
                        // Print the filename.
                        out.print(s);
                        for (int k = list[i].length(); k < 35; k++)
                            out.print(" ");
                        break;
                    case 1:
                        s = Long.toString(file.length());
                        for (int k = 10 - s.length(); k > 0; k--)
                            out.print(" ");
                        // don't cut the size.
                        out.print(s + " ");
                        break;
                    case 2:
                        // cut the description.
                        s = file.isDirectory() ? "DIR" : "";
                        out.print(" " + ((s.length() > 5) ? s.substring(0, 5) : s));
                        for (int k = s.length(); k < 5; k++)
                            out.print(" ");
                        break;
                    case 3:
                        s = new SimpleDateFormat().format(new Date(file.lastModified()));
                        out.print(" " + s);
                    default:
                    }
                }
                // Start with a new line.
                out.println();
            }
            break;
        case 'F':
            int i = 0;
            for (; i < list.length; i++) {
                out.print(list[i] + " ");
                for (int j = list[i].length(); j < 25; j++) {
                    out.print(" ");
                }
                if (i % 3 == 2)
                    out.println();
            }
            if (list.length > 0 && i % 3 != 0) {
                out.println();
            }
            break;
        default:
        } // end of switch

    }

    void pwc() {
        out.println(getPath());
    }

    void cd(String path) {
        String currentPath = webdavResource.getPath();

        try {
            String cdPath = checkUri(path + "/");
            webdavResource.setPath(cdPath);

            if (webdavResource.exists()) {
                if (webdavResource.isCollection()) {
                    setPath(webdavResource.getPath());
                } else {
                    out.println("Warning: Not a collection");
                    webdavResource.setPath(currentPath);
                }
            } else {
                out.println("Warning: Not found the path");
                webdavResource.setPath(currentPath);
            }
        } catch (Exception ex) {
            handleException(ex);
            try {
                webdavResource.setPath(currentPath);
            } catch (Exception e) {
                handleException(e);
            }

        }

        updatePrompt(getPath());
    }

    void ls(String options, String path) {
        // set default option.
        char option = 'F';
        if ((options != null) && (options.indexOf('l') > 0))
            option = 'l';

        try {
            // Check that the path is ok.
            if (path != null) {
                path = checkUri(path + "/");
                webdavResource.setPath(path);
            } else {
                path = checkUri("./");
                webdavResource.setPath(path);
            }
            switch (option) {

            case 'l':

                Vector basiclist = webdavResource.listBasic();
                for (int i = 0; i < basiclist.size(); i++) {
                    String[] longFormat = (String[]) basiclist.elementAt(i);

                    // name -> position 4
                    String s = longFormat[4];
                    int len = s.length();
                    out.print(s);
                    for (int k = len; k < 20; k++)
                        out.print(" ");

                    // size -> position 1            
                    s = longFormat[1];
                    len = s.length();
                    for (int k = 10 - len; k > 0; k--)
                        out.print(" ");
                    // don't cut the size.
                    out.print(s + " ");

                    // description   -> position 2                                
                    // cut the description.
                    s = longFormat[2];
                    len = s.length();

                    out.print(" " + ((len > 20) ? s.substring(0, 20) : s));
                    for (int k = len; k < 20; k++)
                        out.print(" ");

                    // date -> position 3                            
                    s = longFormat[3];
                    len = s.length();
                    out.println(" " + s);
                }

                break;

            case 'F':
                String[] list = webdavResource.list();
                if (list != null) {
                    int i = 0;
                    for (; i < list.length; i++) {
                        out.print(list[i] + " ");
                        for (int j = list[i].length(); j < 25; j++) {
                            out.print(" ");
                        }
                        if (i % 3 == 2)
                            out.println();
                    }
                    if (list.length > 0 && i % 3 != 0)
                        out.println();
                }
                break;
            default:
            } // end of switch
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void propfind(String path, Vector properties) {
        try {
            path = checkUri(path);
            out.print("Getting properties '" + path + "': ");

            Enumeration propertyValues = webdavResource.propfindMethod(path, properties);
            if (propertyValues.hasMoreElements()) {
                while (propertyValues.hasMoreElements()) {
                    out.println(propertyValues.nextElement());
                }
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void status() {
        out.println(webdavResource.getStatusMessage());
    }

    void propfindall(String path) {
        try {
            path = checkUri(path);
            out.print("Getting properties '" + path + "': ");
            Enumeration responses = webdavResource.propfindMethod(path, DepthSupport.DEPTH_0);
            if (!responses.hasMoreElements()) {
                out.println("failed (no response received).");
                out.println(webdavResource.getStatusMessage());
                return;
            } else {
                out.println();
            }
            ResponseEntity response = (ResponseEntity) responses.nextElement();
            Enumeration properties = response.getProperties();
            while (properties.hasMoreElements()) {
                Property property = (Property) properties.nextElement();
                out.println("   " + property.getName() + " : " + property.getPropertyAsString());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void proppatch(String path, String prop, String value) {
        String name = prop;
        try {
            path = checkUri(path);
            out.print("Putting property(" + name + ", " + value + ") to '" + path + "': ");
            if (webdavResource.proppatchMethod(path, new PropertyName("DAV:", name), value, true)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    String getLocalTragetFileName(String path, String filename) {

        String srcFileName = null;
        String tarFileName = null;

        // get traget filename from last portion of path
        StringTokenizer st = new StringTokenizer(path, "/\\");
        while (st.hasMoreTokens()) {
            srcFileName = st.nextToken();
        }

        File targetFile = getFileByPath((filename != null) ? filename : srcFileName);

        try {
            if (targetFile.isDirectory()) {
                tarFileName = targetFile.getCanonicalPath() + "/" + srcFileName;
            } else {
                tarFileName = targetFile.getCanonicalPath();
            }
        } catch (IOException e) {
            System.err.println(e.toString());
            return null;
        }

        return tarFileName;
    }

    void get(String path, String filename) {

        filename = getLocalTragetFileName(path, filename);

        try {
            // The resource on the remote.
            String src = checkUri(path);
            // The file on the local.
            String dest = (filename != null) ? filename
                    : URIUtil.getName(src.endsWith("/") ? src.substring(0, src.length() - 1) : src);

            out.println("get " + src + " " + dest);

            // For the overwrite operation;
            String y = "y";
            File file = new File(dest);
            // Checking the local file.
            if (file.exists()) {

                // FIXME: interactive ?
                out.print("Aleady exists. " + "Do you want to overwrite it(y/n)? ");
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                y = in.readLine();
            }
            if (y.trim().equalsIgnoreCase("y") || (y != null && y.length() == 0)) {
                out.print("Downloading  '" + src + "' to '" + dest + "': ");
                if (webdavResource.getMethod(src, file)) {
                    out.println("succeeded.");
                } else {
                    out.println("failed.");
                    out.println(webdavResource.getStatusMessage());
                }
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    String getRemoteTragetFileName(String filename, String path) {

        String srcPathName = null;
        String target = null;

        // get traget filename from last portion of filename
        StringTokenizer st = new StringTokenizer(filename, "/\\");
        while (st.hasMoreTokens()) {
            srcPathName = st.nextToken();
        }

        try {

            if (path != null) {
                target = checkUri(path);

                // check is path a collection ?
                String currentPath = webdavResource.getPath();

                webdavResource.setPath(target);

                if (webdavResource.exists()) {
                    if (webdavResource.isCollection()) {
                        target += "/" + srcPathName;
                    }
                }

                webdavResource.setPath(currentPath);

            } else {
                target = checkUri(getPath() + "/" + srcPathName);
            }

        } catch (Exception ex) {
        }

        return target;

    }

    void put(String filename, String path) {
        String y = "y";

        try {
            String src = filename;
            String dest = getRemoteTragetFileName(filename, path);

            String currentPath = webdavResource.getPath();

            try {
                webdavResource.setPath(dest);
                if (webdavResource.exists()) {
                    out.print("Aleady exists. " + "Do you want to overwrite it(y/n)? ");
                    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                    y = in.readLine();
                }
                webdavResource.setPath(currentPath);
            } catch (Exception ex) {
            }

            if (y.trim().equalsIgnoreCase("y") || (y != null && y.length() == 0)) {

                File file = getFileByPath(src);

                if (file.exists()) {
                    out.print("Uploading  '" + file.getCanonicalPath() + "' to '" + dest + "' ");

                    if (webdavResource.putMethod(dest, file)) {
                        out.println("succeeded.");
                    } else {
                        out.println("failed.");
                        out.println(webdavResource.getStatusMessage());
                    }
                } else {
                    out.println("Warning: File not exists");
                }
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    // TODO multi
    void delete(String path) {
        try {
            path = checkUri(path);
            out.print("Deleting '" + path + "': ");
            if (webdavResource.deleteMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    // TODO multi
    void mkcol(String path) {
        try {
            path = checkUri(path);
            out.print("Making '" + path + "' collection: ");
            if (webdavResource.mkcolMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void copy(String src, String dst) {
        try {
            src = checkUri(src);
            dst = checkUri(dst);
            out.print("Copying '" + src + "' to '" + dst + "': ");
            if (webdavResource.copyMethod(src, dst)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void move(String src, String dst) {
        try {
            src = checkUri(src);
            dst = checkUri(dst);
            out.print("Moving '" + src + "' to '" + dst + "': ");
            if (webdavResource.moveMethod(src, dst)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void locks(String path) {
        try {
            path = checkUri(path);
            LockDiscoveryProperty lockDiscoveryProperty = webdavResource.lockDiscoveryPropertyFindMethod(path);
            if (lockDiscoveryProperty == null) {
                out.println("Server did not return a LockDiscoveryProperty.");
                out.println(webdavResource.getStatusMessage());
                return;
            }
            Lock[] locks = lockDiscoveryProperty.getActiveLocks();
            showLocks(path, locks);
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void lock(String path, String timeout, String scope, String owner) {
        try {
            // Test the parameter
            //
            // Timeout
            int to = 0;
            if ((timeout != null) && (timeout.toLowerCase().substring(0, 5).equals("-tinf"))) { //infinite
                to = LockMethod.TIMEOUT_INFINITY;
            } else {
                to = (timeout == null) ? 120 : Integer.parseInt(timeout.substring(2));
            }

            // scope
            short scopeType = ((scope != null) && (scope.substring(2).toLowerCase().equals("shared")))
                    ? LockMethod.SCOPE_SHARED
                    : LockMethod.SCOPE_EXCLUSIVE;

            // owner
            owner = (owner != null) ? (owner.substring(2)) : owner;

            path = checkUri(path);
            out.print("Locking '" + path + "' ");
            out.print((owner != null) ? "owner:'" + owner + "' " : "");
            out.print("scope:" + scopeType + " timeout:" + to + " :");
            if (webdavResource.lockMethod(path, owner, to, scopeType)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void unlock(String path, String owner) {
        try {
            // Test the parameter
            //
            // owner
            owner = (owner != null) ? (owner.substring(2)) : owner;

            path = checkUri(path);
            out.print("Unlocking '" + path + "'");
            out.print((owner != null) ? (" owner:" + owner + ": ") : (": "));
            if (webdavResource.unlockMethod(path, owner)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void grant(String permission, String path, String principal) {
        grant(new QName("DAV:", permission), path, principal);

        // FIME lookup permission ?
        //                if (namespace==null) {
        //            namespace=resolveNamespace(permission);
        //            if (namespace==null) {
        //                out.println("Could not resolve namespace for permission " + permission);
        //                continue;
        //            }
        //        }
    }

    void grant(QName permission, String path, String principal) {
        try {
            principal = checkPrincipal(principal, webdavResource, path);
            grant(webdavResource, permission, path, principal);
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void deny(String permission, String path, String principal) {
        deny(new QName("DAV:", permission), path, principal);
    }

    void deny(QName permission, String path, String principal) {
        try {
            principal = checkPrincipal(principal, webdavResource, path);
            deny(webdavResource, permission, path, principal);
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void revoke(String permission, String path, String principal) {
        revoke(new QName("DAV:", permission), path, principal);
    }

    void revoke(QName permission, String path, String principal) {
        try {
            principal = checkPrincipal(principal, webdavResource, path);
            revoke(webdavResource, permission, path, principal);
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void acl(String path) {
        try {
            AclProperty acl = null;
            if (path != null) {
                path = checkUri(path);
            } else {
                path = webdavResource.getPath();
            }
            acl = webdavResource.aclfindMethod(path);

            if (acl == null) {
                out.println("Error: PropFind didn't return an AclProperty!");
                return;
            }
            out.println();
            showAces(path, acl.getAces());
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void principalcollectionset(String path) {
        try {
            PrincipalCollectionSetProperty set = null;
            if (path != null) {
                path = checkUri(path);
            } else {
                path = webdavResource.getPath();
            }
            set = webdavResource.principalCollectionSetFindMethod(path);

            if (set == null) {
                out.println("Error: PropFind didn't return an PrincipalCollectionSetProperty!");
                return;
            }
            String[] hrefs = set.getHrefs();
            if (hrefs == null) {
                out.println("No PrincipalCollectionSet for " + path);
            }
            out.println();
            out.println("PrincipalCollectionSet for " + path + ":");
            for (int i = 0; i < hrefs.length; i++)
                out.println("   " + hrefs[i]);
            out.println();
        } catch (Exception ex) {
        }
    }

    ///////////////////////////////////////////////////////////////////

    void checkin(String path) {
        try {
            path = checkUri(path);
            out.print("checking in '" + path + "': ");
            if (webdavResource.checkinMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void checkout(String path) {
        try {
            path = checkUri(path);
            out.print("checking out '" + path + "': ");
            if (webdavResource.checkoutMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void uncheckout(String path) {
        try {
            path = checkUri(path);
            out.print("unchecking out '" + path + "': ");
            if (webdavResource.uncheckoutMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void versioncontrol(String path) {
        try {
            path = checkUri(path);
            out.print("setting up VersionControl '" + path + "': ");
            if (webdavResource.versionControlMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void versioncontrol(String target, String path) {
        try {
            path = checkUri(path);
            out.print("creating versioncontroled Resource '" + target + "' based on '" + path + "' : ");
            if (webdavResource.versionControlMethod(path, target)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void report(String path, Vector properties) {
        Enumeration propertyValues;
        try {
            path = checkUri(path);
            out.println("Getting version-tree Report of '" + path + "':");

            if ((properties != null) && (properties.size() > 0)) {
                propertyValues = webdavResource.reportMethod(uriToHttpURL(path), properties, 1);
            } else {
                propertyValues = webdavResource.reportMethod(uriToHttpURL(path), 1);
            }

            if (propertyValues.hasMoreElements()) {
                while (propertyValues.hasMoreElements()) {
                    out.println(propertyValues.nextElement().toString());
                }
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void ereport(String path, String srcFilename) {
        try {
            String sQuery = "";
            if (srcFilename == null) {
                sQuery = "<D:expand-property xmlns:D='DAV:'><D:property name='version-history'><D:property name='version-set'><D:property name='successor-set'><D:property name='comment'/></D:property></D:property></D:property></D:expand-property>";
            } else {
                File file = new File(dir.getCanonicalPath(), srcFilename);
                if (!file.exists()) {
                    out.println("report src file not found");
                    return;
                }
                InputStream isQuery = new FileInputStream(file);
                BufferedReader reader = new BufferedReader(new InputStreamReader(isQuery));

                while (reader.ready()) {
                    sQuery += reader.readLine();
                }
                reader.close();

                sQuery.replace('\t', ' ');
                out.println(sQuery);
            }

            path = checkUri(path);
            out.println("expand-property Report of '" + path + "':");

            Enumeration propertyValues = webdavResource.reportMethod(uriToHttpURL(path), sQuery, 1);
            if (propertyValues.hasMoreElements()) {
                while (propertyValues.hasMoreElements()) {
                    out.println(displayXML(propertyValues.nextElement().toString(), 0));
                }
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    /**
     * lreport path properties on historyUris
     */
    void lreport(String path, Vector properties, Vector historyUris) {
        try {
            path = checkUri(path);
            out.println("Getting version-tree Report of '" + path + "':");

            Enumeration propertyValues = webdavResource.reportMethod(uriToHttpURL(path), properties, historyUris,
                    1);
            if (propertyValues.hasMoreElements()) {
                while (propertyValues.hasMoreElements()) {
                    out.println(propertyValues.nextElement().toString());
                }
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void mkws(String path) {
        try {
            path = checkUri(path);
            out.print("Making '" + path + "' workspace: ");
            if (webdavResource.mkWorkspaceMethod(path)) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    /**
     * Update
     *
     * @param path
     * @param version
     */
    void update(String path, String version) {
        try {
            path = checkUri(path);
            out.print("Updateing resource " + path + ": ");
            if (webdavResource.updateMethod(path, version)) {
                out.println("succeeded.");
            } else {
                out.println("failed!");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void beginTransaction(String timeout, String owner) {
        try {
            checkUri(null);

            // Test the parameter
            //
            // Timeout
            int to = 0;
            if ((timeout != null) && (timeout.toLowerCase().substring(0, 5).equals("-tinf"))) { //infinite
                to = LockMethod.TIMEOUT_INFINITY;
            } else {
                to = (timeout == null) ? 120 : Integer.parseInt(timeout.substring(2));
            }

            // owner
            owner = (owner != null) ? (owner.substring(2)) : owner;

            out.print("Starting transaction ");
            if (webdavResource.startTransaction(owner, to)) {
                out.println("succeeded.");
                out.println("Handle: '" + webdavResource.getTransactionHandle() + "'");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void commitTransaction() {
        try {
            checkUri(null);

            out.print("Committing transaction: '" + webdavResource.getTransactionHandle() + "' ");
            if (webdavResource.commitTransaction()) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    void abortTransaction() {
        try {
            checkUri(null);

            out.print("Rolling back transaction: '" + webdavResource.getTransactionHandle() + "' ");
            if (webdavResource.abortTransaction()) {
                out.println("succeeded.");
            } else {
                out.println("failed.");
                out.println(webdavResource.getStatusMessage());
            }
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    ///////////////////////////////////////////////////////////////////
    // Support methods
    ///////////////////////////////////////////////////////////////////

    private void setDisplayPrompt(boolean displayPrompt) {
        this.displayPrompt = displayPrompt;
    }

    /**
     * Determine which URI to use at the prompt.
     *
     * @param uri the path to be set.
     * @return the absolute path.
     */
    private String checkUri(String uri) throws IOException {

        if (webdavResource == null) {
            throw new IOException("Not connected yet.");
        }

        if (uri == null) {
            uri = webdavResource.getPath();
        }

        if (!uri.startsWith("/")) {
            uri = getPath() + uri;
        }

        return normalize(uri);
    }

    private String checkPrincipal(String principal, WebdavResource webdavResource, String path)
            throws HttpException, IOException {
        // Do not complete reserved words
        String[] types = { "all", "authenticated", "unauthenticated", "property", "self" };
        for (int i = 0; i < types.length; i++) {
            if (types[i].equals(principal))
                return principal;
        }

        // FIXME: when search support is complete enhance this
        //        to really search for the principal
        if (!principal.startsWith("/") && !principal.startsWith("http")) {
            PrincipalCollectionSetProperty set = webdavResource.principalCollectionSetFindMethod(path);
            if ((set != null) && (set.getHrefs() != null) && (set.getHrefs().length == 1))
                principal = set.getHrefs()[0] + "/" + principal;
        }
        return normalize(principal);
    }

    /**
     * Set the path.
     *
     * @param path the path string.
     */
    private void setPath(String path) {
        if (!path.endsWith("/")) {
            path = path + "/";
        }

        this.path = normalize(path);
    }

    /**
     * Get the path.
     *
     * @return the path string.
     */
    private String getPath() {
        return path;
    }

    /**
     * Update the command prompt for the display.
     *
     * @param path the path string
     */
    private void updatePrompt(String path) {
        StringBuffer buff = new StringBuffer();
        try {
            buff.append("[" + httpURL.getHost().toUpperCase() + ":");
            buff.append(path + "] ");
            buff.append(dir.getCanonicalPath());

        } catch (Exception e) {
            buff.append("[ Slide ]");
        }
        buff.append(" $ ");
        commandPrompt = buff.toString();
    }

    /**
     * Get the prompt.
     *
     * @return the prompt to be displayed.
     */
    private String getPrompt() {
        return commandPrompt;
    }

    /**
     * Return a context-relative path, beginning with a "/", that represents
     * the canonical version of the specified path after ".." and "." elements
     * are resolved out.  If the specified path attempts to go outside the
     * boundaries of the current context (i.e. too many ".." path elements
     * are present), return <code>null</code> instead.
     *
     * @param path the path to be normalized.
     * @return the normalized path.
     */
    private String normalize(String path) {
        if (path == null)
            return null;

        String normalized = path;

        // Normalize the slashes and add leading slash if necessary
        if (normalized.indexOf('\\') >= 0)
            normalized = normalized.replace('\\', '/');
        if (!normalized.startsWith("/"))
            normalized = "/" + normalized;

        // Resolve occurrences of "/./" in the normalized path
        while (true) {
            int index = normalized.indexOf("/./");
            if (index < 0)
                break;
            normalized = normalized.substring(0, index) + normalized.substring(index + 2);
        }

        // Resolve occurrences of "/../" in the normalized path
        while (true) {
            int index = normalized.indexOf("/../");
            if (index < 0)
                break;
            if (index == 0)
                return ("/"); // The only left path is the root.
            int index2 = normalized.lastIndexOf('/', index - 1);
            normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
        }

        // Resolve occurrences of "//" in the normalized path
        while (true) {
            int index = normalized.indexOf("//");
            if (index < 0)
                break;
            normalized = normalized.substring(0, index) + normalized.substring(index + 1);
        }

        // Return the normalized path that we have completed
        return (normalized);
    }

    /**
     * Print the Slide client commands for use
     */
    private void printSlideClientUsage() {
        out.println("Commands:");
        out.println("  options {http_URL|path}       " + "Print available http methods");
        out.println("  open [http_URL]               " + "Connect to specified URL");
        out.println("  close                         " + "Close current connection");
        out.println("  exit                          " + "Exit Slide");
        out.println("  help                          " + "Print this help message");
        out.println("  debug {ON|OFF}                " + "set debugmode");
        out.println("  lpwd                          " + "Print local working directory");
        out.println("  lcd [path]                    " + "Change local working directory");
        out.println("  lls [-lF] [path]              " + "List contents of local directory");
        out.println("  pwc                           " + "Print working collection");
        out.println("  cc [path]                     " + "Change working collection");
        out.println("  ls [-lF] [path]               " + "List contents of collection");
        out.println("  url                           " + "Print working URL");
        out.println("  status                        " + "Print latest http status message");
        out.println("  get path [file]               " + "Get a resource to a file");
        out.println("  put {URL|file} [path]         " + "Put a given file or URL to path");
        out.println("  mkcol path ...                " + "Make new collections");
        out.println("  delete path ...               " + "Delete resources");
        out.println("  copy source destination       " + "Copy resource from source to destination path");
        out.println("  move source destination       " + "Move resource from source to destination path");
        out.println("  lock path [-t(xxx|inf)] " + "[-s(SHARED|EXCLUSIVE)] [-oOWNER]\n"
                + "                                " + "Lock specified resource.\n"
                + "                                " + "default:\n" + "                                "
                + "lock file -t120 -sexclusive with current owner");
        out.println("  unlock path [-oOWNER]         " + "Unlock specified resource.\n"
                + "                                " + "default:\n" + "                                "
                + "unlock file with current owner");
        out.println("  locks [<path>]                " + "Displays locks on specified resource");
        out.println("  propget path property ...     " + "Print value of specified property");
        out.println("  propgetall [<path>]           " + "Print value of all properties");
        out.println("  propput path property value   " + "Set property with given value");
        out.println("  set URLencode {on|off}        " + "Set URL encoding flag, default: on");
        out.println("  set debug {on|off}            " + "Set debug level, default: off");
        out.println("  acl [<path>]                  " + "Displays the ACL of path");
        out.println("  principalcol [<path>]         " + "Displays the principal collection set of path");
        out.println("  grant  [<namespace>] <permission> [on <path>] to <principal>");
        out.println("  deny   [<namespace>] <permission> [on <path>] to <principal>");
        out.println("  revoke [<namespace>] <permission> [on <path>] from <principal>");
        out.println("  versioncontrol path           " + "set a versionable resource under versioncontrol");
        out.println("  versioncontrol URL path       "
                + "create a new versioncontrolled resource at path based on history URL");
        out.println("  checkout path                 " + "checkout of a checkedin resource");
        out.println("  checkin path                  " + "checkin of a checkedout resource");
        out.println("  uncheckout path               "
                + "undoing changes on Resource since checkedout (including checkout)");
        out.println("  report path [<property>]      " + "getting report (version-tree) for any resource");
        out.println("  eReport path                  " + "getting report (expand-property) for any resource");
        out.println("  LReport path [<property>] ON [<historyuri>] " + "getting report (locate-by-history)");
        out.println("  mkws path ...                 " + "Make new workspace");
        out.println("  update path target                 "
                + "Update a resource identified by path to version identified by target");
        out.println("  begin                          starts a new transaction (only if server supports this)");
        out.println(
                "  commit                         commits the transaction started by begin (only if server supports this)");
        out.println(
                "  abort                          aborts and rolls back the transaction started by begin (only if server supports this)");
        out.println("Aliases: help=?, open=connect, ls=dir, pwc=pwd, cc=cd, "
                + "lls=ldir, copy=cp,\n move=mv, delete=del=rm, mkcol=mkdir, "
                + "propget=propfind, propput=proppatch,\n exit=quit=bye");
        out.println("Comment : Once executed, the debug mode will "
                + "be active.\n\t\tBecause it's not triggered by " + "methods yet.");
    }

    /**
     * Sleep
     */
    //    private static void pause(int secs)
    //    {
    //
    //        try {
    //            Thread.sleep( secs * 1000 );
    //        } catch( InterruptedException ex ) {
    //        }
    //    }

    //    private String resolveNamespace(String permission)
    //    {
    //        String DEFAULT_NAMESPACE = "DAV:";
    //        String SLIDE_NAMESPACE = "http://jakarta.apache.org/slide/";
    //        String namespace=null;
    //
    //        if (permission==null)
    //            return null;
    //
    //        if ((permission.equalsIgnoreCase("all")) ||
    //            (permission.equalsIgnoreCase("read")) ||
    //            (permission.equalsIgnoreCase("write")) ||
    //            (permission.equalsIgnoreCase("read-acl")) ||
    //            (permission.equalsIgnoreCase("write-acl")))
    //        {
    //            namespace=DEFAULT_NAMESPACE;
    //        }
    //
    //        if ((permission.equalsIgnoreCase("read-object")) ||
    //            (permission.equalsIgnoreCase("read-revision-metadata")) ||
    //            (permission.equalsIgnoreCase("read-revision-content")) ||
    //            (permission.equalsIgnoreCase("create-object")) ||
    //            (permission.equalsIgnoreCase("remove-object")) ||
    //            (permission.equalsIgnoreCase("lock-object")) ||
    //            (permission.equalsIgnoreCase("read-locks")) ||
    //            (permission.equalsIgnoreCase("create-revision-metadata")) ||
    //            (permission.equalsIgnoreCase("modify-revision-metadata")) ||
    //            (permission.equalsIgnoreCase("remove-revision-metadata")) ||
    //            (permission.equalsIgnoreCase("create-revision-content")) ||
    //            (permission.equalsIgnoreCase("modify-revision-content")) ||
    //            (permission.equalsIgnoreCase("remove-revision-content")) ||
    //            (permission.equalsIgnoreCase("grant-permission")) ||
    //            (permission.equalsIgnoreCase("revoke-permission")))
    //        {
    //            namespace=SLIDE_NAMESPACE;
    //        }
    //
    //        return namespace;
    //    }

    private boolean grant(WebdavResource webdavResource, QName permission, String path, String principal)
            throws HttpException, IOException {
        out.println("grant " + permission + " on " + path + " to " + principal);
        return addPermission(webdavResource, permission, path, principal, false);
    }

    private boolean deny(WebdavResource webdavResource, QName permission, String path, String principal)
            throws HttpException, IOException {
        out.println("deny " + permission + " on " + path + " to " + principal);
        return addPermission(webdavResource, permission, path, principal, true);
    }

    private boolean revoke(WebdavResource webdavResource, QName permission, String path, String principal)
            throws HttpException, IOException {
        out.println("revoke " + permission + " on " + path + " from " + principal);
        return removePermission(webdavResource, permission, path, principal);
    }

    private boolean addPermission(WebdavResource webdavResource, QName permission, String path, String principal,
            boolean negative) throws HttpException, IOException {

        AclProperty acl = webdavResource.aclfindMethod(path);
        if (acl == null) {
            out.println("Error: PropFind didn't return an AclProperty!");
            return false;
        }
        Ace[] aces = acl.getAces();

        if (aces == null)
            aces = new Ace[0];

        if (debugLevel > 5) {
            out.println();
            out.println("ACL from server");
            showAces(path, aces);
        }

        Ace ace = null;
        for (int i = 0; i < aces.length && (ace == null); i++) {
            if ((aces[i].isNegative() == negative) && !aces[i].isProtected() && !aces[i].isInherited()
                    && aces[i].getPrincipal().equals(principal)) {
                if (debugLevel > 5)
                    out.println("found ace");
                ace = aces[i];
            }
        }
        if (ace == null) {
            Ace[] oldAces = aces;
            aces = new Ace[oldAces.length + 1];
            System.arraycopy(oldAces, 0, aces, 0, oldAces.length);
            ace = new Ace(principal, negative, false, false, null);
            aces[oldAces.length] = ace;
        }

        Privilege privilege = new Privilege(permission.getNamespaceURI(), permission.getLocalName(), null);
        ace.addPrivilege(privilege);

        if (debugLevel > 5) {
            out.println();
            out.println("ACL with updated privileges");
            showAces(path, aces);
        }

        boolean success = webdavResource.aclMethod(path, aces);

        if (!success)
            out.println(webdavResource.getStatusMessage());

        if (debugLevel > 5) {
            acl = webdavResource.aclfindMethod(path);
            if (acl == null)
                out.println("Error: PropFind didn't return an AclProperty!");
            else {
                aces = acl.getAces();
                out.println();
                out.println("ACL from server after update");
                showAces(path, aces);
            }
        }

        return success;
    }

    private boolean removePermission(WebdavResource webdavResource, QName permission, String path, String principal)
            throws HttpException, IOException {
        AclProperty acl = webdavResource.aclfindMethod(path);
        if (acl == null) {
            out.println("Error: PropFind didn't return an AclProperty!");
            return false;
        }
        Ace[] aces = acl.getAces();

        if (aces == null) {
            out.println("Privilege not found");
            return false;
        }

        if (debugLevel > 5) {
            out.println();
            out.println("ACL from server");
            showAces(path, aces);
        }

        boolean found = false;
        Privilege privilege = new Privilege(permission.getNamespaceURI(), permission.getLocalName(), null);
        for (int i = 0; i < aces.length; i++) {
            if (!aces[i].isProtected() && !aces[i].isInherited() && aces[i].getPrincipal().equals(principal)) {
                if (debugLevel > 5)
                    out.println("found ace");
                boolean removed = aces[i].removePrivilege(privilege);
                found = found || removed;
                if (removed)
                    out.println("Privilege removed");
            }
        }

        if (!found) {
            out.println("Privilege not found");
            return false;
        }

        if (debugLevel > 5) {
            out.println();
            out.println("ACL with updated privileges");
            showAces(path, aces);
        }

        boolean success = webdavResource.aclMethod(path, aces);

        if (!success)
            out.println(webdavResource.getStatusMessage());

        if (debugLevel > 5) {
            acl = webdavResource.aclfindMethod(path);
            if (acl == null)
                out.println("Error: PropFind didn't return an AclProperty!");
            else {
                aces = acl.getAces();
                out.println();
                out.println("ACL from server after update");
                showAces(path, aces);
            }
        }

        return success;
    }

    private void showAces(String path, Ace[] aces) {
        if ((aces == null) || (aces.length == 0)) {
            out.println("ACL for " + path + " is empty.");
            return;
        }

        out.println("ACL for " + path + ":");
        out.println("------------------------------------------------------------");
        for (int i = 0; i < aces.length; i++) {
            Ace ace = aces[i];
            out.println((!ace.isNegative() ? "granted" : "denied") + " to " + ace.getPrincipal() + " " + "   ("
                    + (ace.isProtected() ? "protected" : "not protected") + ")" + "   ("
                    + (ace.isInherited() ? ("inherited from '" + ace.getInheritedFrom() + "'") : "not inherited")
                    + ")");

            Enumeration privileges = ace.enumeratePrivileges();
            while (privileges.hasMoreElements()) {
                Privilege priv = (Privilege) privileges.nextElement();
                out.println("   " + priv.getNamespace() + priv.getName() + "   "
                        + (priv.getParameter() == null ? "" : ("(" + priv.getParameter() + ")")));
            }
        }
        out.println("------------------------------------------------------------");
    }

    private void showLocks(String path, Lock[] locks) {
        if ((locks == null) || (locks.length == 0)) {
            out.println("No locks on " + path);
            return;
        }

        out.println("Locks for " + path + ":");
        out.println("------------------------------------------------------------");
        for (int i = 0; i < locks.length; i++) {
            int lockScope = locks[i].getLockScope();
            if (lockScope == Lock.SCOPE_EXCLUSIVE) {
                out.print("Exclusive ");
            } else if (lockScope == Lock.SCOPE_SHARED) {
                out.print("Shared ");
            } else if (lockScope == -1) {
                out.print("Unknown scope ");
            } else {
                out.println("!!! Internal error !!!");
                return;
            }

            int lockType = locks[i].getLockType();
            if (lockType == Lock.TYPE_WRITE) {
                out.println("write lock");
            } else if (lockType == -1) {
                out.println("unknown type");
            } else {
                out.println("!!! Internal error !!!");
                return;
            }

            int depth = locks[i].getDepth();
            if (depth == DepthSupport.DEPTH_INFINITY) {
                out.println("   depth: infinity");
            } else if (depth == -1) {
                // unknown
            } else {
                out.println("   depth: " + depth);
            }

            String owner = locks[i].getOwner();
            if (owner != null)
                out.println("   owner: " + owner);

            int timeout = locks[i].getTimeout();
            if (timeout != -1)
                out.println("   timeout: " + timeout);

            String token = locks[i].getLockToken();
            if (token != null)
                out.println("   token: " + token);
        }
    }

    private String displayXML(String xmlString, int count) {
        String sResult = "";

        if (xmlString.startsWith("</")) {
            count--;
            //out.println("cl: " + count);
            for (int cc = count; cc > 0; cc--) {
                sResult += "\t";
            }

            try {
                sResult += xmlString.substring(0, xmlString.indexOf(">") + 1) + "\n";
                xmlString = xmlString.substring(xmlString.indexOf(">") + 1);
                //count --;
                sResult += displayXML(xmlString, count);
            } catch (Exception any) {
                //sResult += "endtag" + any;
            }

        } else if (xmlString.startsWith("<")) {
            //out.println("op: " + count);
            for (int cc = count; cc > 0; cc--) {
                sResult += "\t";
            }
            try {
                sResult += xmlString.substring(0, xmlString.indexOf(">") + 1) + "\n";
                xmlString = xmlString.substring(xmlString.indexOf(">") + 1);
                count++;
                sResult += displayXML(xmlString, count);
            } catch (Exception any) {
                //sResult += "starttag" + any;
            }
        } else {
            //out.println("em: " + count);
            for (int cc = count; cc > 0; cc--) {
                sResult += "\t";
            }
            try {
                sResult += xmlString.substring(0, xmlString.indexOf("<")) + "\n";
                xmlString = xmlString.substring(xmlString.indexOf("<"));
                sResult += displayXML(xmlString, count);
            } catch (Exception any) {
                //sResult += any;
            }
        }
        return sResult;
    }

    private static HttpURL uriToHttpURL(String uri) throws URIException {
        return uri.startsWith("https") ? new HttpsURL(uri) : new HttpURL(uri);
    }
}