Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/sun/net/ftp/FtpClient.java

/*
 * @(#)FtpClient.java	1.32 95/10/18 Jonathan Payne
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package sun.net.ftp;

import java.util.StringTokenizer;
import java.io.*;
import java.net.*;
import java.lang.SecurityManager;
import sun.net.TransferProtocolClient;
import sun.net.TelnetInputStream;
import sun.net.TelnetOutputStream;

/**
 * This class implements the FTP client. 
 *
 * @version	1.32, 18 Oct 1995
 * @author	Jonathan Payne
 */

public class FtpClient extends TransferProtocolClient {
    public static final int FTP_PORT = 21;

    static int	FTP_SUCCESS = 1;
    static int	FTP_TRY_AGAIN = 2;
    static int	FTP_ERROR = 3;

    /** socket for data transfer */
    private Socket	dataSocket = null;
    private boolean	replyPending = false;
    private boolean	binaryMode = false;

    /** user name for login */
    String		user = null;
    /** password for login */
    String		password = null;

    /** last command issued */
    String		command;

    /** The last reply code from the ftp daemon. */
    int			lastReplyCode;

    /* these fields are used to determine whether ftp urls are sent to */
    /* an http server instead of using a direct connection to the */
    /* host. They aren't used directly here. */
    public static boolean	useFtpProxy = Boolean.getBoolean("ftpProxySet");
    public static String	ftpProxyHost = getPropertyFtpProxyHost();
    public static int		ftpProxyPort = Integer.getInteger("ftpProxyPort", 80).intValue();

    
    private static String getPropertyFtpProxyHost() {
	SecurityManager.setScopePermission();
	return(System.getProperty("ftpProxyHost"));
    }

    /** 
     * issue the QUIT command to the FTP server and close the connection. 
     */
    public void closeServer() throws IOException {
	if (serverIsOpen()) {
	    issueCommand("QUIT");
	    super.closeServer();
	}
    }

    protected int issueCommand(String cmd) throws IOException {
	command = cmd;

	int reply;

	if (replyPending) {
	    if (readReply() == FTP_ERROR)
		System.out.print("Error reading pending reply\n");
	}
	replyPending = false;
	do {
	    sendServer(cmd + "\r\n");
	    reply = readReply();
	} while (reply == FTP_TRY_AGAIN);
	return reply;
    }

    protected void issueCommandCheck(String cmd) throws IOException {
	if (issueCommand(cmd) != FTP_SUCCESS)
	    throw new FtpProtocolException(cmd);
    }

    protected int readReply() throws IOException {
	lastReplyCode = readServerResponse();

	switch (lastReplyCode / 100) {
	case 1:
	    replyPending = true;
	    /* falls into ... */

	case 2:
	case 3:
	    return FTP_SUCCESS;

	case 5:
	    if (lastReplyCode == 530) {
		if (user == null) {
		    throw new FtpLoginException("Not logged in");
		}
		return FTP_ERROR;
	    }
	    if (lastReplyCode == 550) {
		throw new FileNotFoundException(command + ": " + getResponseString());
	    }
	}

	/* this statement is not reached */
	return FTP_ERROR;
    }

    protected Socket openDataConnection(String cmd) throws IOException {
	ServerSocket portSocket;
	String	    portCmd;
	InetAddress myAddress = InetAddress.getLocalHost();
	byte	    addr[] = myAddress.getAddress();
	int	    shift;
	IOException e;

	portSocket = new ServerSocket(0, 1);
	portCmd = "PORT ";

	/* append host addr */
	for (int i = 0; i < addr.length; i++) {
	    portCmd = portCmd + (addr[i] & 0xFF) + ",";
	}

	/* append port number */
	portCmd = portCmd + ((portSocket.getLocalPort() >>> 8) & 0xff) + ","
		+ (portSocket.getLocalPort() & 0xff);
	if (issueCommand(portCmd) == FTP_ERROR) {
	    e = new FtpProtocolException("PORT");
	    portSocket.close();
	    throw e;
	}
	if (issueCommand(cmd) == FTP_ERROR) {
	    e = new FtpProtocolException(cmd);
	    portSocket.close();
	    throw e;
	}
	dataSocket = portSocket.accept();
	portSocket.close();

	return dataSocket;
    }

    /* public methods */

    /** open a FTP connection to host <i>host</i>. */
    public void openServer(String host) throws IOException {
	int port = FTP_PORT;

	/*
	String source = Firewall.verifyAccess(host, port);

	if (source != null) {
	    Firewall.securityError("Applet at " +
				   source +
				   " tried to open FTP connection to "
				   + host + ":" + port);
	    return;
	}
	*/
	openServer(host, port);
    }

    /** open a FTP connection to host <i>host</i> on port <i>port</i>. */
    public void openServer(String host, int port) throws IOException {
	/*
	String source = Firewall.verifyAccess(host, port);

	if (source != null) {
	    Firewall.securityError("Applet at " +
				   source +
				   " tried to open FTP connection to "
				   + host + ":" + port);
	    return;
	}
	*/
	super.openServer(host, port);
	if (readReply() == FTP_ERROR)
	    throw new FtpProtocolException("Welcome message");
    }


    /** 
     * login user to a host with username <i>user</i> and password 
     * <i>password</i> 
     */
    public void login(String user, String password) throws IOException {
	/* This is bogus.  It shouldn't send a password unless it
       	needs to. */

	if (!serverIsOpen())
	    throw new FtpLoginException("not connected to host");
	this.user = user;
	this.password = password;
	if (issueCommand("USER " + user) == FTP_ERROR)
	    throw new FtpLoginException("user");
	if (password != null && issueCommand("PASS " + password) == FTP_ERROR)
	    throw new FtpLoginException("password");
    }

    /** GET a file from the FTP server */
    public TelnetInputStream get(String filename) throws IOException {
	Socket	s;

	try {
//	    throw new FileNotFoundException("Just kidding!");
	    s = openDataConnection("RETR " + filename);
	} catch (FileNotFoundException fileException) {
	    /* Well, "/" might not be the file delimitor for this
	       particular ftp server, so let's try a series of
	       "cd" commands to get to the right place. */
	    StringTokenizer t = new StringTokenizer(filename, "/");
	    String	    pathElement = null;

	    while (t.hasMoreElements()) {
		pathElement = t.nextToken();

		if (!t.hasMoreElements()) {
		    /* This is the file component.  Look it up now. */
		    break;
		}
		try {
		    cd(pathElement);
		} catch (FtpProtocolException e) {
		    /* Giving up. */
		    throw fileException;
		}
	    }
	    if (pathElement != null) {
		s = openDataConnection("RETR " + pathElement);
	    } else {
		throw fileException;
	    }
	}

	return new FtpInputStream(this, s.getInputStream(), binaryMode);
    }

    /** PUT a file to the FTP server */
    public TelnetOutputStream put(String filename) throws IOException {
	Socket s = openDataConnection("STOR " + filename);

	return new TelnetOutputStream(s.getOutputStream(), binaryMode);
    }

    /** LIST files on a remote FTP server */
    public TelnetInputStream list() throws IOException {
	Socket s = openDataConnection("LIST");

	return new TelnetInputStream(s.getInputStream(), binaryMode);
    }

    /** CD to a specific directory on a remote FTP server */
    public void cd(String remoteDirectory) throws IOException {
	issueCommandCheck("CWD " + remoteDirectory);
    }

    /** Set transfer type to 'I' */
    public void binary() throws IOException {
	issueCommandCheck("TYPE I");
	binaryMode = true;
    }

    /** Set transfer type to 'A' */
    public void ascii() throws IOException {
	issueCommandCheck("TYPE A");
	binaryMode = false;
    }

    /** New FTP client connected to host <i>host</i>. */
    public FtpClient(String host) throws IOException {
	super();
	openServer(host, FTP_PORT);
    }

    /** New FTP client connected to host <i>host</i>, port <i>port</i>. */
    public FtpClient(String host, int port) throws IOException {
	super();
	openServer(host, port);
    }

    /** Create an uninitialized FTP client. */
    public FtpClient() {}
}