[jcifs] Abstract File(File, SmbFile) and enhanced Servlet application

Rolf Breuning Rolf.Breuning at t-online.de
Sun May 30 14:18:51 GMT 2004


Skipped content of type multipart/alternative-------------- next part --------------
/*
 * ExplorerServlet.java
 *
 * Created on 30. Mai 2004, 14:02
 */

package jcifs.http;

import java.io.*;
import java.net.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.ecs.*;
import org.apache.ecs.html.*;
import com.oreilly.servlet.multipart.MultipartParser;
import com.oreilly.servlet.multipart.Part;
import com.oreilly.servlet.multipart.FilePart;
import com.oreilly.servlet.multipart.ParamPart;

import jcifs.smb.*;
import jcifs.util.MimeMap;
import jcifs.util.AbstractFile;

/**
 *
 * @author  Rolf Breuning (Rolf.Breuning at t-online.de)
 */
public class ExplorerServlet extends javax.servlet.http.HttpServlet {

    String servletPath;    
    
    static final String Cmd = "cmd";
    static final String CmdStart = "Cmd";
    static final String CmdRootAddDialog = "CmdRootAddDialog";
    static final String CmdRootAdd = "CmdRootAdd";
    static final String CmdRootSelect = "CmdRootSelect";
    static final String CmdDirectoryList = "CmdDirectoryList";
    static final String CmdDirectoryCreate = "CmdDirectoryCreate";
    static final String CmdFileSend = "CmdFileSend";
    static final String CmdFileRemoveDialog = "CmdFileRemoveDialog";
    static final String CmdFileRemove = "CmdFileRemove";
    static final String CmdFileRenameDialog = "CmdFileRenameDialog";
    static final String CmdFileRename = "CmdFileRename";
    static final String CmdFileUpload = "CmdFileUpload";
    
    static final String FldRootFiles = "FldRootFiles";
    static final String FldLocalFile = "FldLocalFile";
    static final String FldDomain = "FldDomain";
    static final String FldServer = "FldServer";
    static final String FldShare = "FldShare";
    static final String FldUser = "FldUser";
    static final String FldPass = "FldPass";
    static final String FldPort = "FldPort";
    static final String FldChkBox = "FldChk";
    static final String FldPathInput = "FldPathInput";
    static final String FldUploadFile = "FldUploadFile";
    static final String FldUploadUnzip = "FldUploadUnzip";
    static final String FldNewDir = "FldNewDir";
    
    static final String Sort = "Srt";
    
    static final String StyTitle = "StyTitle";
    static final String StyTrMark = "StyTrMark";
    static final String StyTdHead = "StyTdHead";
    
    static final String AtrRootFiles = "RootFiles";
    static final String AtrRootIndex = "RootIndex";
    static final String AtrFileHandler = "FileHandler";
    
    static final String Encoding = "utf-8";
    
    static final DateFormat FileDateFormat = new SimpleDateFormat( "yy-MM-dd HH:mm:ss" );
    
    static final Comparator CmpType = new Comparator() { public int compare( Object a, Object b ) {
        try {
            boolean aDir = ( (AbstractFile) a).getAbsoluteURL().endsWith( "/" );
            boolean bDir = ( (AbstractFile) b).getAbsoluteURL().endsWith( "/" );
            if ( aDir == bDir ) return CmpPath.compare( a, b );
            return ( aDir ? -1 : 1 );
        } catch (Exception exc) { return 0;}
    } };
    static final Comparator CmpPath = new Comparator() { public int compare( Object a, Object b ) {
        return ( (AbstractFile) a).getName().compareToIgnoreCase( ( (AbstractFile) b).getName() );
    } };
    static final Comparator CmpSize = new Comparator() { public int compare( Object a, Object b ) {
        long result = 0;
        try { result += ( (AbstractFile) a).length(); } catch (Exception exc) {};
        try { result -= ( (AbstractFile) b).length(); } catch (Exception exc) {};
        if ( result == 0 ) return 0; else return ( result > 0 ) ? 1 : -1;
    } };
    static final Comparator CmpLastModified = new Comparator() { public int compare( Object a, Object b ) {
        long result = 0;
        try { result += ( (AbstractFile) a).lastModified(); } catch (Exception exc) {};
        try { result -= ( (AbstractFile) b).lastModified(); } catch (Exception exc) {};
        if ( result == 0 ) return 0; else return ( result > 0 ) ? 1 : -1;
    } };
    
    
    
    /**
     * Return the first string in the enumeration 'e' starting with 'start'.
     *
     * Creation date: (01.10.00 17.15.36)
     * @return java.lang.String
     * @param e java.util.Enumeration
     * @param start java.lang.String
     */
    static public String getStringStartingWith(java.util.Enumeration e, String start ) {
        String current;
        for ( ; e.hasMoreElements(); ) {
            current = (String) e.nextElement();
            if ( current.startsWith( start ) ) return current;
        };
        return null;
    }
    
    
    /** Return the HTML <head> elements including the title
     * @param title
     * @return
     */
    protected String getHeadElements( String title ) {
        return "<head>\n  <title>" +  title + "</title>\n" +
        "  <style type=\"text/css\">\n" +
        "    body	 { font-family:sans-serif; text-align:justify; }\n" +
        "    td            { font-family:sans-serif; }\n" +
        "    input       { font-family:sans-serif; }\n" +
        "    a:link       { color:blue; text-decoration:underline; }\n" +
        "    a:visited { color:blue; text-decoration:underline; }\n" +
        "    a:active 	{ color:red; text-decoration:none; }\n" +
        "    #StyTitle	{ font-family:sans-serif; font-size:18px; font-weight:bold; }\n" +
        "    #StyTrMark { background-color:#c0c0c0; }\n" +
        "    #StyTdHead { background-color:#c0c0c0; font-weight:bold; }\n" +
        "  </style>\n" +
        "  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + Encoding + "\" >\n" +
        "</head>";
    }
    
    /** Create directory. Called from cmdDirectoryList(). 'filename' is the file "download.zip" in the directory where the new directory is created
     * @param base
     * @param directory
     * @param req an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @throws Exception
     */
    protected void cmdDirectoryCreate(HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String filename ) throws Exception {
        AbstractFile dir = base.getChild( filename ).getParent();
        String newName = req.getParameter( FldNewDir );
        newName = newName.replace( '\\', '/' );
        if ( newName.startsWith( "/" ) ) newName = newName.substring(1);
        if ( ! newName.endsWith( "/" ) ) newName += "/";
        dir.getChild( newName ).mkdirs();
        resp.sendRedirect( "." );
    }

    /**
     *
     * @param req  	an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp	an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @exception IOException	if an input or output error is detected when the servlet handles the GET request
     * @exception ServletException	if the request for the GET could not be handled
     */
    protected void cmdDirectoryList(HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String directory ) throws Exception {
        AbstractFile dir = base.getChild( directory );
        AbstractFile files[] = new AbstractFile[0];
        files = dir.listFiles();
        String sort = req.getParameter( Sort );
        Comparator cmp = CmpType;
        if ( "P".equals( sort ) ) cmp = CmpPath;
        if ( "S".equals( sort ) ) cmp = CmpSize;
        if ( "L".equals( sort ) ) cmp = CmpLastModified;
        Arrays.sort( files, cmp );
       
        Table table = new Table().setBorder(0).setCellPadding( 0 ).setCellSpacing( 0 ).setWidth( "100%");
        table.addElement( new TR()
            .addElement( new TD( new A().setHref( "?" + Sort + "=T" ).addElement( "Type" ) ).setID( StyTdHead) )
            .addElement( new TD().setWidth( 5 ) )
            .addElement( new TD( new A().setHref( "?" + Sort + "=P" ).addElement( "Path" ) ).setID( StyTdHead) )
            .addElement( new TD().setWidth( 5 ) )
            .addElement( new TD( new A().setHref( "?" + Sort + "=S" ).addElement( "Size" ) ).setID( StyTdHead) )
            .addElement( new TD().setWidth( 5 ) )
            .addElement( new TD( new A().setHref( "?" + Sort + "=L" ).addElement( "Last modified" ) ).setID( StyTdHead) )
            );
        sort = ( sort == null ) ? "" : "?" + Sort + "=" + sort;
        int pos = directory.lastIndexOf( "/" );
        if ( pos > 0 ) {
            table.addElement( new TR()
                .addElement( new TD("D") )
                .addElement( new TD() )
                .addElement( new TD( new A().setHref( "../" + sort ).addElement( ".." ) ) )
            );
        };
        String basePath = base.getAbsoluteURL();
        for ( int i=0; i<files.length; i++ ) {
            AbstractFile file = files[i];
            String path = file.getAbsoluteURL().substring( basePath.length() );
            String name = file.getName();
            long length = 0;
            String fileSign = "-";
            String link = URLEncoder.encode( name );
            if ( file.isDirectory() ) { name += "/"; link += "/"; fileSign = "D"; }
            if ( file.isFile() ) fileSign = "F";
            try { length = file.length(); } catch (Exception exc) {};
            table.addElement( new TR()
                .addElement( new TD()
                    .addElement( fileSign )
                    .addElement( new Input( Input.CHECKBOX, FldChkBox, name ) ) )
                .addElement( new TD() )
                .addElement( new TD( new A().setHref( link + sort).addElement( name ) ) )
                .addElement( new TD() )
                .addElement( new TD( "" + length ).setAlign( "right" ) )
                .addElement( new TD() )
                .addElement( new TD( FileDateFormat.format( new Date( file.lastModified() ) ) ) )
            );
        };
        new Html()
            .addElement( new ClearElement( getHeadElements( "FB: " + directory ) ) )
            .addElement( new Body()
                .addElement( new ClearElement( showTopLine( req, base ) ) )
                .addElement( "Directory: " )
                .addElement( new A().setHref( "./" + sort ).addElement( dir.toString() ) )
                .addElement( new Form()
                    .setMethod( Form.POST )
                    .setAction( "download.zip" )
                    .addElement( table )
                    .addElement( "Selected:" )
                    .addElement( new Input( Input.SUBMIT, CmdFileSend, "Download" ) )
                    .addElement( new Input( Input.SUBMIT, CmdFileRemoveDialog, "Remove..." ) )
                    .addElement( new Input( Input.SUBMIT, CmdFileRenameDialog, "Rename to:" ) )
                    .addElement( new Input( Input.text, FldPathInput, "" ) )
                    .addElement( new BR() )
                    .addElement( new BR() ) 
                    .addElement( new Table().setCellPadding(3).setCellSpacing(0).setBorder(0)
                        .addElement( new TR()
                            .addElement( new TD( "Create directory:" ) )
                            .addElement( new TD( new Input( Input.text, FldNewDir, "" ).setSize( 30 ) ) )
                            .addElement( new TD( new Input( Input.submit, CmdDirectoryCreate, "Create" ) ) )
                            .setID( StyTrMark )
                        ) ) )
                .addElement( new Form()
                    .setMethod( Form.POST )
                    .setEncType( Form.ENC_UPLOAD )
                    .setAction( "" )
                    .addElement( new Table().setCellPadding(3).setCellSpacing(0).setBorder(0)
                        .addElement( new TR()
                            .addElement( new TD( "Upload file:" ) )
                            .addElement( new TD()
                                .addElement( new Input( Input.file, FldUploadFile, "" ).setSize( 30 ) )
                                .addElement( new BR() )
                                .addElement( new Input( Input.CHECKBOX, FldUploadUnzip, FldUploadUnzip ) )
                                .addElement( "Unzip after upload" )
                            )
                            .addElement( new TD( new Input( Input.SUBMIT, CmdFileUpload, "Upload" ) ) )
                            .setID( StyTrMark )
                        )
                    )
                )
            )
            .output( resp.getWriter() );
    }
    
    /**
     * Remove file dialog, called from cmdDirectoryList. 'filename' is the file "download.zip" in the directory where the files
     * identified by the names by parameters are to be removed
     * @param base
     * @param fileName
     * @param req an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @throws Exception
     */
    protected void cmdFileRemoveDialog( HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String fileName ) throws Exception {
        String selected[] = req.getParameterValues( FldChkBox );
        AbstractFile dir = base.getChild( fileName ).getParent();
        if ( selected == null ) selected = new String[0];
        Table table = new Table().setCellPadding(0).setCellSpacing(0).setBorder(0)
            .addElement( new TR()
                .addElement( new TD( "File" ).setID( StyTdHead ) ) );
        for ( int i=0; i<selected.length; i++) {
            table.addElement( new TR()
                .addElement( new TD()
                    .addElement( new Input( Input.HIDDEN, FldChkBox, selected[i] ) )
                    .addElement( selected[i] ) ) );
        };
        
        new Html()
            .addElement( new ClearElement( getHeadElements( "FB: " + dir ) ) )
            .addElement( new Body()
                .addElement( new ClearElement( showTopLine( req, base ) ) )
                .addElement( new Form()
                    .setMethod( Form.POST )
                    .setAction( "." ) // Point to the directory from the URL, not the download file
                    .addElement( "Remove in directory: " + dir )
                    .addElement( table )
                    .addElement( new Input( Input.SUBMIT, CmdFileRemove, "Remove" ) )
                    .addElement( new Input( Input.SUBMIT, CmdDirectoryList, "Cancel" ) )
                    )
                )
            .output( resp.getWriter() );
    }
    
    /**
     * Remove file dialog, called from cmdFileRemoveDialog.
     * @param base
     * @param directory
     * @param req an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @throws Exception
     */
    protected void cmdFileRemove( HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String directory ) throws Exception {
        String selected[] = req.getParameterValues( FldChkBox );
        AbstractFile dir = base.getChild( directory );
        if ( selected == null ) selected = new String[0];
        Table table = new Table().setCellPadding(0).setCellSpacing(0).setBorder(0)
            .addElement( new TR()
                .addElement( new TD( "File" ).setID( StyTdHead ) )
                .addElement( new TD().setWidth( 5 ) )
                .addElement( new TD( "Status" ).setID( StyTdHead ) ) );
        for ( int i=0; i<selected.length; i++) {
            Exception exception = null;
            try { dir.getChild( selected[i] ).delete(); }
            catch ( Exception exc ) { exception = exc; };
            table.addElement( new TR()
                .addElement( new TD( selected[i] ) )
                .addElement( new TD() )
                .addElement( new TD( exception == null ? "removed" : "fail" ) ) );
        };
        new Html()
            .addElement( new ClearElement( getHeadElements( "FB: " + dir ) ) )
            .addElement( new Body()
                .addElement( new ClearElement( showTopLine( req, base ) ) )
                .addElement( "Removed in directory: " + dir )
                .addElement( table )
                .addElement( new Form()
                    .addElement( new Input( Input.SUBMIT, CmdDirectoryList, "Go on" ) ) )
                )
            .output( resp.getWriter() );
    }
    
    /**
     * Rename file. 'filename' is the file "download.zip" in the directory where the files
     * identified by the names by parameters are to be renamed
     * 'dialog' == true: called from cmdDirectoryList, display dialog only.
     * 'dialog' == false: called from dialog, actual rename
     * @param base
     * @param fileName
     * @param req an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @throws Exception
     */
    protected void cmdFileRename( HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String fileName, boolean dialog ) throws Exception {
        String selected[] = req.getParameterValues( FldChkBox );
        AbstractFile dir = base.getChild( fileName );
        if ( dialog ) dir = dir.getParent();
        String renamePath = req.getParameter( FldPathInput );
        if ( selected == null ) selected = new String[0];
        Table table = new Table().setCellPadding(0).setCellSpacing(0).setBorder(0)
            .addElement( new TR()
                .addElement( new TD( "File" ).setID( StyTdHead ) )
                .addElement( new TD().setWidth( 3 ) )
                .addElement( new TD( "->" ).setID( StyTdHead ) )
                .addElement( new TD().setWidth( 3 ) )
                .addElement( new TD( "New name" ).setID( StyTdHead ) )
                );
        for ( int i=0; i<selected.length; i++) {
            String newName = renamePath.replaceFirst( "\\*", selected[i] );   // * -> last part of old file name
            AbstractFile newFile = dir.createFromURL( dir.getChild( newName ).getAbsoluteURL() );
            TR row = new TR();
            String success = "";
            if ( ! newFile.getAbsoluteURL().startsWith( base.getAbsoluteURL() ) ) {
                success = "Not allowed"; row.setBgColor( "#FF0000" ); 
            } else if ( ! dialog ) { // rename
                success = "ok";
                try { dir.getChild( selected[i] ).renameTo( newFile ); }
                catch ( Exception exc ) { success = "fail"; row.setBgColor( "#FF0000" ); };
            }
            table.addElement( row
                .addElement( new TD()
                    .addElement( new Input( Input.HIDDEN, FldChkBox, selected[i] ) )
                    .addElement( selected[i] ) )
                .addElement( new TD() )
                .addElement( new TD( success ) )
                .addElement( new TD() )
                .addElement( new TD( newFile.toString() ) ) );
        };
        
        new Html()
            .addElement( new ClearElement( getHeadElements( "FB: " + dir ) ) )
            .addElement( new Body()
                .addElement( new ClearElement( showTopLine( req, base ) ) )
                .addElement( new Form()
                    .setMethod( Form.POST )
                    .setAction( "." ) // Point to the directory from the URL, not the download file
                    .addElement( "Rename in directory: " + dir )
                    .addElement( new Input( Input.HIDDEN, FldPathInput, renamePath ) )
                    .addElement( table )
                    .addElement(   dialog ? new Input( Input.SUBMIT, CmdFileRename, "Rename" ) : null )
                    .addElement(   dialog ? new Input( Input.SUBMIT, CmdDirectoryList, "Cancel" ) : null )
                    .addElement( ! dialog ? new Input( Input.SUBMIT, CmdDirectoryList, "Go on" ) : null )
                    )
                )
            .output( resp.getWriter() );
    }
    
    
    /**
     * @param base
     * @param fileName
     * @param req
     * @param resp
     * @throws Exception
     */
    protected void cmdFileSend(HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String fileName ) throws Exception {
        String selected[] = req.getParameterValues( FldChkBox );
        AbstractFile file = base.getChild( fileName );
        if ( selected != null && selected.length > 0 ) { // Download zipped selected files
            base = file.getParent();
            AbstractFile files[] = new AbstractFile[selected.length];
            for ( int i=0; i<files.length; i++) files[i] = base.getChild( selected[i] );
            resp.setContentType( "file/download" );
            ZipOutputStream zip = new ZipOutputStream( resp.getOutputStream() );
            AbstractFile.zip( zip, base.getAbsoluteURL(), "", files );
            zip.close();
        } else { // Download single file without zipping
            InputStream in = file.getInputStream();
            long length = file.length();
            ServletOutputStream out = resp.getOutputStream();
            String url = file.getAbsoluteURL();
            int n = url.lastIndexOf( '.' );
            String type = null;
            if ( n > 0 && (type = url.substring(n+1)).length() > 1 && type.length() < 6 ) {
                type = new MimeMap().getMimeType( type );
            };
            resp.setContentType( type == null ? "file/download" : type );
            resp.setHeader( "Content-Length", length + "" );
            resp.setHeader( "Accept-Ranges", "Bytes" );
            AbstractFile.copy( in, out, new byte[16000] );
            out.close();
        };
    }
    
    /**
     * @param base
     * @param directory
     * @param req
     * @param resp
     * @throws Exception
     */
    protected void cmdFileUpload(HttpServletRequest req, HttpServletResponse resp, AbstractFile base, String directory ) throws Exception {
        AbstractFile dir = base.getChild( directory );

        Table table = new Table().setCellPadding(0).setCellSpacing(0).setBorder(0)
            .addElement( new TR()
                .addElement( new TD( "File" ).setID( StyTdHead ) )
                .addElement( new TD().setWidth( 5 ) )
                .addElement( new TD( "Status" ).setID( StyTdHead ) ) );

        // Parse the incoming multipart, storing files in the dir provided
	MultipartParser parser = new MultipartParser( req, 100000000 );
        AbstractFile file = null;
	Part part;
        boolean unzip = false;
        ElementContainer fileNames = new ElementContainer();
	while ( (part = parser.readNextPart() ) != null ) {
		String name = part.getName();
		if ( part.isParam() ) {
			ParamPart paramPart = (ParamPart) part;
                        String value = paramPart.getStringValue();
                        if ( FldUploadUnzip.equals( name ) && FldUploadUnzip.equals( value ) ) unzip = true;
		} else if ( part.isFile() ) {
			FilePart filePart = (FilePart) part;
			String fileName = filePart.getFileName();
			if ( fileName != null) { // The part actually contained a file
                            file = dir.getChild( fileName );
                            OutputStream stream = file.getOutputStream( false ); 
                            filePart.writeTo( stream );
                            stream.close();
                            fileNames
                                .addElement( new BR() )
                                .addElement( fileName );
			};
		}
	}
        if ( file != null ) { 
            if ( unzip ) { // unzip the uploaded file
                AbstractFile.unzip( file.getInputStream(), "", dir );
                file.delete();
            };
            table.addElement( new TR()
                .addElement( new TD( "" + file ) )
                .addElement( new TD() )
                .addElement( new TD( unzip ? "uploaded, unzipped" : "uploaded" ) ) );
        };
        
        new Html()
            .addElement( new ClearElement( getHeadElements( "FB: " + dir ) ) )
            .addElement( new Body()
                .addElement( new ClearElement( showTopLine( req, base ) ) )
                .addElement( "Uploaded to directory: " + dir )
                .addElement( table )
                .addElement( new Form()
                    .addElement( new Input( Input.SUBMIT, CmdDirectoryList, "Go on" ) ) )
                )
            .output( resp.getWriter() );              
    }

    /**
     * @param rootFile
     * @param req an {@link HttpServletRequest} object that contains the request the client has made of the servlet
     * @param resp an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @exception Exception if the request could not be handled
     */
    protected void cmdRootDialog(HttpServletRequest req, HttpServletResponse resp, AbstractFile rootFile ) throws Exception {
        resp.getWriter().write(
        "<html>" + getHeadElements( "FB: Add new root" ) +
        "<body>\n" + showTopLine( req, rootFile) +
        "<form method=POST action=\"?\">\n" +
        "  <input type=hidden name=" + CmdRootAdd + ">\n" +
        "  <table border=0 cellspacing=0 cellpadding=2>\n" +
        "    <tr><td colspan=2>Access local directory on WWW-server:</td></tr>\n" +
        "    <tr><td>Name:</td><td><input type=text name=" + FldLocalFile + "></td></tr>\n" +
        "    <tr><td colspan=2></td></tr>\n" +
        "    <tr><td colspan=2>Access directory on SMB / CIFS server:</td></tr>\n" +
        "    <tr><td>Domain:</td><td><input type=text name=" + FldDomain + "></td></tr>\n" +
        "    <tr><td>Server:</td><td><input type=text name=" + FldServer + "></td></tr>\n" +
        "    <tr><td>Port:</td><td><input type=text name=" + FldPort + "></td></tr>\n" +
        "    <tr><td>Share:</td><td><input type=text name=" + FldShare + "></td></tr>\n" +
        "    <tr><td>User:</td><td><input type=text name=" + FldUser + "></td></tr>\n" +
        "    <tr><td>Password:</td><td><input type=password name=" + FldPass + "></td></tr>\n" +
        "    <tr><td colspan=2></td></tr>\n" +
        "    <tr><td colspan=2><input type=submit value=\"Add new Root\"></td></tr>\n" +
        "  </table>\n" +
        "</body></html>" );
    }
    
    /**
     *
     * @param req  	an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp	an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @exception Exception	if the request for the GET could not be handled
     */
    protected void cmdRootAdd(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        AbstractFile base;
        String localFile = req.getParameter( "FldLocalFile" ).trim();
        if ( ! "".equals( localFile ) ) { // Local file
            File file = new File( localFile );
            if ( ! file.isDirectory() ) throw new Exception( "Local file is not a directory" );
            base = new AbstractFile.AFFile( file );
        } else { // SMB file
            // user = <user>:<pwd>@
            String pwd = req.getParameter( FldPass );
            String user = req.getParameter( FldUser );
            // domain = <domain>;
            String domain = req.getParameter( FldDomain );
            if ( pwd.length() > 0 ) pwd = ":" + pwd;
            if ( user.length() > 0 ) user = user + pwd + "@";
            if ( domain.length() > 0 ) domain = domain + ";";
            
            // share = <share>/
            String share = req.getParameter( FldShare );
            while ( share.startsWith( "/" ) ) share = share.substring( 1 );
            while ( share.endsWith( "/" ) ) share = share.substring( 0, share.length() -1 );
            if ( share.length() > 0 ) share += "/";
            // server = server:<port>
            String port = req.getParameter( FldPort ).trim();
            String server = req.getParameter( FldServer );
            server += ( port.length() > 0 ) ? ":" + port : "";
            
            String url = "smb://" + domain + user + server + "/" + share;
            base = new AbstractFile.AFSmbFile( url );
        };
        Vector rootFiles = getRootFiles( req );
        rootFiles.add( base );
        resp.sendRedirect( servletPath + "/" + (rootFiles.size() - 1) + "/?" + CmdDirectoryList + "=" );
    }
    
    
    /**
     *
     * @param req  	an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @exception ServletException	if the request for the GET could not be handled
     */
    protected Vector getRootFiles(HttpServletRequest req) {
        Vector rootFiles = (Vector) req.getSession().getAttribute( AtrRootFiles );
        if ( rootFiles == null ) rootFiles = new Vector();
        req.getSession().setAttribute( AtrRootFiles, rootFiles );
        return rootFiles;
    }
    
    
    /**
     *
     * @param req  	an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp	an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @exception ServletException	if the request for the GET could not be handled
     */
    protected String showTopLine( HttpServletRequest req, AbstractFile selectedRoot ) throws Exception {
        String select = "<select name=\"" + FldRootFiles + "\">\n";
        Vector rootFiles = getRootFiles( req );
        for ( int i=0; i<rootFiles.size(); i++ ) {
            AbstractFile file = (AbstractFile) rootFiles.elementAt( i );
            select += "<option value=" + i + (file == selectedRoot ? " selected" : "") + ">" + file.toString() + "</option>\n";
        };
        select += "</select>\n";
        return
        "<table border=0 cellpadding=1 cellspacing=2 width=100% bgcolor=#c0c0c0>\n" +
        "  <tr><td><center id=" + StyTitle + ">File Browser - Rolf Breuning</center></td></tr>\n" +
        "  <tr><td>" +
        "    <form method=POST>\n" + select +
        "      <input type=submit name=" + CmdRootSelect + " value=\"Select root\">\n" +
        "      <input type=submit name=" + CmdRootAddDialog + " value=\"Add new root...\">\n" +
        "    </form>" +
        "  </td></tr>" +
        "</table><br>";
    }
    
    /**
     *
     * @param req  	an {@link HttpServletRequest} object that contains the request the client has made	of the servlet
     * @param resp	an {@link HttpServletResponse} object that contains the response the servlet sends to the object
     * @exception IOException	if an input or output error is detected when the servlet handles the GET request
     * @exception ServletException	if the request for the GET could not be handled
     */
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType( "text/html; charset=" + Encoding );
        if ( req.getCharacterEncoding() == null ) req.setCharacterEncoding( Encoding );
        
        //	req = ServletUtil.getMultipartRequest( req, uploadDir.getAbsolutePath(), "" + ++uploadAccess, 100000000 );
        String cmd = (String) req.getAttribute( Cmd );
        if ( cmd == null ) cmd = getStringStartingWith( req.getParameterNames(), CmdStart );
        if ( cmd == null ) cmd = (String) req.getParameter( Cmd );
        if ( cmd != null && cmd.indexOf( "." ) >= 0 ) cmd = cmd.substring( 0, cmd.indexOf( "." ) );
        
        servletPath =  req.getContextPath() + req.getServletPath();
        String pathInfo = req.getPathInfo();
        if ( pathInfo.startsWith( "/" ) ) pathInfo = pathInfo.substring( 1 );
        int pos = pathInfo.indexOf( "/" );
        AbstractFile rootFile = null;
        try {
            int rootIndex = Integer.parseInt( pathInfo.substring( 0, pos ) );
            pathInfo = pathInfo.substring( pos+1 );
            rootFile = (AbstractFile) getRootFiles( req ).elementAt( rootIndex );
            rootFile.getAttributes().put( AtrRootIndex, new Integer( rootIndex ) );
        } catch ( Exception exc ) {};
        if ( rootFile == null && ! CmdRootAdd.equals(cmd) ) cmd = CmdRootAddDialog;
        if ( cmd == null ) cmd = ( pathInfo.length() == 0 || pathInfo.endsWith( "/" ) ) ? CmdDirectoryList : CmdFileSend;
        String contentType = req.getContentType();
	if ( contentType != null && contentType.toLowerCase().startsWith( "multipart/form-data" ) ) cmd = CmdFileUpload;

        try {
            if ( CmdRootAddDialog.equals(cmd) )                 cmdRootDialog( req, resp, rootFile );
            else if ( CmdRootAdd.equals( cmd ) )                 cmdRootAdd( req, resp );
            else if ( CmdDirectoryList.equals( cmd ) )           cmdDirectoryList( req, resp, rootFile, pathInfo );
            else if ( CmdDirectoryCreate.equals( cmd ) )      cmdDirectoryCreate( req, resp, rootFile, pathInfo );
            else if ( CmdRootSelect.equals( cmd ) )             resp.sendRedirect( servletPath + "/" + req.getParameter( FldRootFiles ) + "/" );
            else if ( CmdFileSend.equals( cmd ) )                 cmdFileSend( req, resp, rootFile, pathInfo );
            else if ( CmdFileRemoveDialog.equals( cmd ) )  cmdFileRemoveDialog( req, resp, rootFile, pathInfo );
            else if ( CmdFileRemove.equals( cmd ) )            cmdFileRemove( req, resp, rootFile, pathInfo );
            else if ( CmdFileRenameDialog.equals( cmd ) )  cmdFileRename( req, resp, rootFile, pathInfo, true );
            else if ( CmdFileRename.equals( cmd ) )            cmdFileRename( req, resp, rootFile, pathInfo, false );
            else if ( CmdFileUpload.equals( cmd ) )              cmdFileUpload( req, resp, rootFile, pathInfo );
        } catch ( Exception exc ) {
            throw new ServletException( exc );
        };
    }
        
}
-------------- next part --------------
/*
 * AbstractFile.java
 * This class provides an extendable abstraction of files. An AbstractFile can represent: <ul>
 * <li>A local file as implemented by java.lang.File.</li>
 * <li>a SMB based file implemented by jcifs.smb.SmbFile </li>
 * </ul>
 * AbstractFile itself is a superclass providing some basic functions, like createFromURL() and a list of abstract functions
 * For each kind of file a subclass has been created (inner subclasses are used only to keep AbstractFile in one file)
 * AbstractFile.AFFile / AbstractFile.AFSmbFile implement the abstract functions based on File / SmbFile.
 * <br>
 * Possible extensions can use registerFactory() to add new schemes and file types - e.g. NFS based or compressed file systems
 * AbstractFile also provides generic copy / unzip / zip functions, which facilitate transfer of files / directory trees among various file systems.
 *
 * Created on 30. Mai 2004, 13:37
 */

package jcifs.util;

import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.util.zip.*;
import jcifs.smb.*;

/**
 *
 * @author  Rolf Breuning (Rolf.Breuning at t-online.de)
 */
public abstract class AbstractFile {
    protected static Map factories = new java.util.HashMap();
    protected Map attributes; // Extend the file by arbitrary user defined extensions
        
    public static interface AbstractFileFilter {
        public boolean accept( AbstractFile file );
    };
    
    public static AbstractFileFilter AFFAll = new AbstractFileFilter() { 
        public boolean accept( AbstractFile file ) { return true; };
    };
    
    /**
     * Register an AbstractFile as a 'factory' for given 'scheme'. 
     * The factory will be used to create new AbstractFiles using the AbstractFile.fromURL( url ) method.
     * The url for files to be created with the factory have the form [scheme]:[pathname]. 
     * @param scheme String
     * @param factory AbstractFile, used as factory
     */    
    public static void registerFactory( String scheme, AbstractFile factory ) {
        factories.put( scheme, factory );
    };

    static { 
        registerFactory( AFFile.scheme, new AFFile() );
        registerFactory( AFSmbFile.scheme, new AFSmbFile() );
    };

    
    /**
     * Create a new AbstractFile from the 'url'. 'url' is of the form [scheme]:[pathname].
     * The creation will be redirected to the createFromUrl() method of the factory registered for the [scheme].
     * @param url String
     * @return AbstractFile
     */
    public static AbstractFile fromURL( String url ) throws Exception {
        String scheme = url.split( ":" ) [0];
        AbstractFile factory = (AbstractFile) factories.get( scheme );
        return factory.createFromURL( url ); 
    }
        
    /**
     * Create a new instance of the receiver's class for the given 'url' of the form [scheme]:[pathname]
     * This method allows the receiver to be used as a factory for new abstract files of the same class. 
     * @param url String
     * @throws Exception
     * @return
     */    
    public abstract AbstractFile createFromURL( String url ) throws Exception;
        
    /** Return true if the file / directory represented by the receiver exists
     * @throws Exception
     * @return */    
    public abstract boolean exists() throws Exception;
    
    /** Return the absolute url name of the receiver. 
     * The result ends on "/" for a directory and without "/" for usual files.
     * @throws Exception
     * @return */    
    public abstract String getAbsoluteURL() throws Exception;
    
    /** Return a generic map of attributes free for use of the application programmer
     * @return */    
    public Map getAttributes() { if ( attributes == null ) attributes = new java.util.HashMap(); return attributes; }

    /** Return the file or directory name, i.e. the last element of the full path. Always without any path separators.
     * @throws Exception
     * @return */    
    public abstract String getName();
    
    /** Create a new abstract file or directory defined by the combination of the receiver's url and the 'path'. 
     * The receiver must be a directory. The 'path' contains directory names and possibly a file name, separated by "/".
     * @param path
     * @throws Exception
     * @return */    
    public abstract AbstractFile getChild( String path ) throws Exception;
    
    /** Return the directory where the receiver is located in.
     * @throws Exception
     * @return */
    public abstract AbstractFile getParent() throws Exception;
    
    /** The receiver must represent a file. Return an input stream which allows to read the file contents.
     * @throws Exception
     * @return */    
    public abstract InputStream getInputStream() throws Exception;

    /** The receiver must represent a file. Return an output stream which allows to write to the file.
     * If 'append' is true, add any new contents to the end of the file
     * @return
     * @param append
     * @throws Exception
     */    
    public abstract OutputStream getOutputStream( boolean append ) throws Exception;
    
    /** Return the length of the file or directory in bytes.
     * @throws Exception
     * @return */    
    public abstract long length() throws Exception;
    
    /** Return the last modified time of the receiver in milliseconds since January 1st, 1970
     * @throws Exception
     * @return */    
    public abstract long lastModified() throws Exception;
    
    /** Return true if the receiver is a directory
     * @throws Exception
     * @return */    
    public abstract boolean isDirectory() throws Exception;
    
    /** Return true if the receiver is a file
     * @throws Exception
     * @return */    
    public abstract boolean isFile() throws Exception;
    
    /** Delete the receiver. If the receiver is a directory, also delete its contents.
     * @throws Exception */    
    public abstract void delete() throws Exception;

    /** Create the receiver directory and if necessary its parents
     * @throws Exception */    
    public abstract void mkdirs() throws Exception;

    /** Rename the file identified by the receiver to the 'target' file. 
     * This effects the actual file identified, both the receiver object and the target object will remain unchanged.
     * @param target
     * @throws Exception
     */    
    public abstract void renameTo( AbstractFile target ) throws Exception;
    
    /** List all files or directories which are direct children of the receiver.
     * @throws Exception
     * @return */    
    public abstract AbstractFile[] listFiles() throws Exception;
    
    /** List files or directories which are direct children of the receiver and which match the 'filter'.
     * @param filter
     * @throws Exception
     * @return */    
    public AbstractFile[] listFiles(AbstractFileFilter filter) throws Exception {
        AbstractFile files[] = listFiles();
        int r = 0;
        for ( int i=0; i<files.length; i++ )
            if ( filter.accept( files[i] ) ) files[r++] = files[i];
        AbstractFile result[] = new AbstractFile[r];
        System.arraycopy( files, 0, result, 0, r );
        return result;
    };
    
    /**
    * Copy all bytes from the 'in' stream to the 'out' stream, until the 'in' stream is finished and
    * return the number of bytes copied. Use 'buffer' to copy the bytes.
    * Depending on the 'in' stream's implementation the method can block (idle or busy) 
    * until the 'in' stream is finished.
    *
    * <br>Creation date: (23.08.00 19.14.34)
    *
    * return long
    * @param in java.io.InputStream
    * @param out java.io.OutputStream
    * @param buffer byte[]
 * @exception java.io.IOException The exception description.
 */
    public final static long copy(java.io.InputStream in, java.io.OutputStream out, byte buffer[] ) throws java.io.IOException {
        int length;
        long totalLength = 0;
	while ( ( length = in.read( buffer ) ) >= 0 ) {
            totalLength += length;
            out.write( buffer, 0, length );
	};
	return totalLength;
}

    
    /** All files in 'files' will be added to the 'zipStream'. All directories in 'files' will be added
     * recursively including all files and subdirectories, even empty subdirectories. If 'files' contains a directory
     * exactely matching the 'basePath', there will be no entry for this directory, only for the recursive contents.
     * <p>
     * File names will be stored with their absolute path names. If such a name includes the 'basePath' and /
     * or a leading path separator, these parts will be removed from the name. The 'newBasePath' will be added
     * as a leading base path.
     *
     * Creation date: (10.02.2002 21:48:43)
     * @param newBasePath
     * @param zipStream
     * @param baseURL Start of URL pointing to a directory to be removed from the beginning of each file's URL
     * @param files Array of AbstracFiles to be copied into the 'zipStream' including all subdirectories
     * @throws Exception
     */
public static void zip(ZipOutputStream zipStream, String baseURL, String newBasePath, AbstractFile files[]) throws Exception {
    AbstractFile sourceFile;
    String sourceURL;
    String destEntry;
    InputStream sourceStream = null;
    // Ersure baseURL is a canonical directory name ending with "/", newBasePath end without "/" -> remaining zip path never starts with "/"
    if ( ! baseURL.endsWith( "/" ) ) baseURL += "/";
    AbstractFile baseDir = AbstractFile.fromURL( baseURL );
    if ( ! baseDir.isDirectory() ) throw new Exception( "'baseURL' must point to valid directory" );
    baseURL = baseDir.getAbsoluteURL();
    if ( newBasePath.endsWith( "/" ) ) newBasePath = newBasePath.substring( 0, newBasePath.length()-1 );
    Vector allFiles = new Vector( Arrays.asList( files ) );
    try { 
	for ( int i=0; i<allFiles.size(); i++ ) { // Note: 'allFiles' may grow when including directories
            sourceFile = (AbstractFile) allFiles.elementAt(i);
            sourceURL = sourceFile.getAbsoluteURL();
            if ( sourceURL.startsWith( baseURL ) ) sourceURL = sourceURL.substring( baseURL.length() );
            destEntry = newBasePath + sourceURL;
            if ( sourceFile.isDirectory() ) { // directory, add subelements to 'allFiles'
                if ( sourceURL.length() > 0 ) zipStream.putNextEntry( new ZipEntry( destEntry ) );
		allFiles.addAll( Arrays.asList( sourceFile.listFiles() ) );
            } else {
                zipStream.putNextEntry( new ZipEntry( destEntry ) );
                sourceStream = sourceFile.getInputStream();
		copy( sourceStream, zipStream, new byte[16000] );
		sourceStream.close();
            };
            zipStream.closeEntry();
        };
    } finally {
        try { sourceStream.close(); } catch ( Exception exc ) {};
    }
}


    /** The 'inputStream' contains data of a zip file which can be processed via java.util.ZipInputStream.
     * Extract the subdirectory starting with "path" and all files and directories included in this subdirectory 
     * to the 'directory'. path = "" will extract all files included.
     * All necessary directories will be created. The 'inputStream' will be closed at the end.
     * <br>
     * Example:
     * <br>The 'in' stream contains the following files: a/a1.txt, a/a2.txt, b/b1.txt, b/b2.txt
     * <br>unzip( in, "b", AbstractFile.fromURL( "file://c:/x/" ) )  is called on a Windows machine
     * <br>This will extract b/b1.txt -> c:\x\b1.txt, b/b2.txt -> c:\x\b2.txt. 
     *
     * Creation date: (10.02.2002 21:48:43)
     * @param inputStream
     * @param directory
     * @throws Exception
     */
public static void unzip(InputStream inputStream, String path, AbstractFile directory ) throws Exception {
    ZipInputStream in = new ZipInputStream( inputStream );
    ZipEntry entry;
    if ( path.length() > 0 && ! path.endsWith( "/" ) ) path += "/";
    
    for ( ; ( entry = in.getNextEntry() ) != null ; ) { // Process next entry
        String targetName = entry.getName();
        if ( ! targetName.startsWith( path ) ) continue;
        targetName = targetName.substring( path.length() );
        AbstractFile targetFile = directory.getChild( targetName );
        if ( entry.isDirectory() ) {
            targetFile.mkdirs();
        } else {
            targetFile.getParent().mkdirs();
            OutputStream targetStream = targetFile.getOutputStream( false );
            copy( in, targetStream, new byte[16000] );
            targetStream.close();
        };
        in.closeEntry();
    };
    in.close();
}

    public static class AFFile extends AbstractFile {
        protected java.io.File file;
        protected boolean isDirectory = false; // Valid only if file does not exist
        protected static final String scheme = "file";
        
        /** Return a canonical file name from the url. Please note that this even for directories may end without a trailing file separator 
         * @param url
         * @throws Exception
         * @return
         */        
        public static String fileNameFromURL(String url) throws Exception { 
            String result = url.substring ( (scheme + ":/").length() ).replace('/', File.separatorChar );
            return new File( result ).getCanonicalPath();
        }
        
        protected AFFile() {}; // For factory creation
        public AFFile( String path ) { file = new File( path ); isDirectory = path.endsWith( File.separator ); };
        public AFFile( File aFile, boolean isDirectory ) { file = aFile; this.isDirectory = isDirectory; };
        public AFFile( File aFile ) { file = aFile; };
        public AbstractFile createFromURL(String url) throws Exception { return new AFFile( new File( fileNameFromURL(url) ), url.endsWith( "/" ) ); }
        public boolean exists() throws Exception { return file.exists(); }
        public String getAbsoluteURL() throws Exception { 
            String result = "file:/" + file.getAbsolutePath().replace( File.separatorChar, '/' );
            if ( ! result.endsWith( "/" ) && isDirectory() ) result += "/";
            return result;
        }
        public String getName() { return file.getName(); }
        public AbstractFile getChild(String path) throws Exception { return createFromURL( getAbsoluteURL() + path ); }
        public AbstractFile getParent() throws Exception { return new AFFile( file.getParent() ); }
        public InputStream getInputStream() throws Exception { return new FileInputStream( file ); }
        public OutputStream getOutputStream(boolean append) throws Exception { return new FileOutputStream( file, append ); }        
        public boolean isDirectory() throws Exception { return file.exists() ? file.isDirectory() : isDirectory; }
        public boolean isFile() throws Exception { return file.isFile(); }
        public long lastModified() throws Exception { return file.lastModified(); }
        public long length() throws Exception { return file.length(); }
        public void delete() throws Exception { 
            if ( file.isDirectory() ) { // recursive delete
                String names[] = file.list();
                if ( names == null ) throw new IOException( "Could not open file list of directory: " + file.getPath() );
                for ( int i=0; i < names.length; i++ ) new AFFile( new File( file, names[i] ) ).delete();
            };
            if ( ! file.delete() ) throw new IOException( "Could not remove file or directory: " + file.getPath() );
        }
        public void mkdirs() throws Exception { 
            if ( exists() && isDirectory() ) return; 
            if ( ! file.mkdirs() ) throw new Exception("Could not create directory"); 
        }
        public AbstractFile[] listFiles() throws Exception {
            File files[] = file.listFiles();
            AbstractFile result[] = new AbstractFile[ files.length ];
            for (int i=0; i<files.length; i++ )
                result[i] = new AFFile( files[i] );
            return result;
        }
        public void renameTo(AbstractFile target) throws Exception { 
            if ( ! (target instanceof AFFile) ) throw new Exception( "target must be of same type than receiver" );
            if ( ! file.renameTo( ( (AFFile) target).file ) ) throw new Exception( "Could not rename file");
        }
        public String toString() { return "file:/" + file.getAbsolutePath().replace( File.separatorChar, '/' ); }
               
    }
    
    public static class AFSmbFile extends AbstractFile {
        protected SmbFile smbFile;
        protected static final String scheme = "smb";
        static final Pattern pwdPattern = Pattern.compile( "/|(:[^(/@)]*@)" );

        protected AFSmbFile() {}; // For factory creation
        public AFSmbFile( String pathname ) throws Exception { smbFile = new SmbFile( pathname ); };
        public AFSmbFile( SmbFile file ) { smbFile = file; };
        public AbstractFile createFromURL(String url) throws Exception { return new AFSmbFile( url ); }
        public boolean exists() throws Exception { return smbFile.exists(); }
        public String getAbsoluteURL() throws Exception { return smbFile.getCanonicalPath(); }
        public String getName() { return smbFile.getName().replaceAll( "/", "" ); }
        public AbstractFile getChild(String path) throws Exception { return createFromURL( getAbsoluteURL() + path ); }
        public AbstractFile getParent() throws Exception { return new AFSmbFile( smbFile.getParent() ); }
        public InputStream getInputStream() throws Exception { return new SmbFileInputStream( smbFile ); }
        public OutputStream getOutputStream(boolean append) throws Exception { return new SmbFileOutputStream( smbFile, append ); }        
        public boolean isDirectory() throws Exception { return smbFile.isDirectory(); }        
        public boolean isFile() throws Exception { return smbFile.isFile(); }
        public long lastModified() throws Exception { return smbFile.lastModified(); }
        public long length() throws Exception { return smbFile.length(); }
        public void delete() throws Exception { smbFile.delete(); }
        public void mkdirs() throws Exception { if (exists() && isDirectory() ) return; smbFile.mkdirs(); }
        public AbstractFile[] listFiles() throws Exception {
            SmbFile files[] = smbFile.listFiles();
            AbstractFile result[] = new AbstractFile[ files.length ];
            String orgPath = smbFile.getPath();
            for (int i=0; i<files.length; i++ )
                result[i] = new AFSmbFile( orgPath + files[i].getName() );            
            return result;
        }         
        public void renameTo(AbstractFile target) throws Exception {
            if ( ! (target instanceof AFSmbFile) ) throw new Exception( "target must be of same type than receiver" );
            smbFile.renameTo( ( (AFSmbFile) target).smbFile );
        }        

        /** Return a string representing the receiver path in the form smb://.... ; suppress password
         * @return 
         */
        public String toString() { 
            String path = smbFile.getCanonicalPath().substring( 6 ); // remove smb:// from path
            Matcher m = pwdPattern.matcher( path );
            if ( m.find() && path.charAt( m.start() ) == ':' ) path = m.replaceFirst( ":...@" );
            return "smb://" + path;
        }                     
                
    }
}



More information about the jcifs mailing list