Problems with MultiLine responses from ftp server

P

past

Hi All,

I am using FTPSession.java which is based on the Internet Protocol
RFC959.

Through my client FTPSession.java, i am trying to download a file from
a ftp server which has a disclaimer on it.
This disclaimer is a multi line response.

The code of FTPSession, in its getResponse method is coded to handle
multi line responses, but when i connect to the server (it is a NT
server with Unix Style directory system) it gives me a null response
from the server.
It gives me a error in the method "getResponse", bad(short) response
from the server.

The server is not able to log me in as the response i get from the
server is null.
Is it a problem with the FTP server or do i need to handle it in the
FTPClient code.

The code of FTPSession which i am using is as below.

Can someboody please help me on this ASAP, as it is very urgent.

Thanks in advance
past


import java.io.*;
import java.net.*;
import java.util.*;


/**
* A java class used to transmit and receive files or text to a ftp
* server using File Transfer Protocol (FTP) by direct communications
* with the host machine using sockets on port 21.
*
* @param host - hostname running the ftp server to transmit the file
to.
* @param username - username used to log in to the ftp server.
* @param password - password used to log in to the ftp server.
* <p>
* <pre>
* FTPSession ftp = new FTPSession("computer.site.com", "anonymous",
"(e-mail address removed)");
* ftp.uploadFile("test.dat", (ftp.readFile("test.dat").toString());
* StringBuffer sb = ftp.downloadFile("test.dat");
* ftp.writeFile("new_"+ "test.dat",sb.toString());
* </pre>
*
*
*/

public class FTPSession
{
protected String username = null;
protected String password = null;
protected Socket sessionSocket = null;
protected Socket dataSocket = null;
protected String host = null;
protected String reply = null;
protected DataInputStream inStream = null;
protected DataOutputStream outStream = null;
protected PrintStream printStream = null;
protected boolean loggedIn = false;
protected static final String ASCII = "A";
protected static final String BINARY = "I";
protected static final int port = 21;
protected String transferType = BINARY;

/**
* A java class used to transmit and receive files or text to a ftp
* server using File Transfer Protocol (FTP) by direct communications
* with the host machine using sockets on port 21.
*
* @param host - hostname running the ftp server to transmit the file
to.
* @param username - username used to log in to the ftp server.
* @param password - password used to log in to the ftp server.
*/

public FTPSession(String _host, String _username, String _password)
{
this(_host,_username,_password,BINARY);
}

/**
* @param host - hostname running the ftp server to transmit the file
to.
* @param username - username used to log in to the ftp server.
* @param password - password used to log in to the ftp server.
* @param transferType - ASCII or BINARY transfer format (BINARY is
default).
*/
public FTPSession(String _host, String _username,
String _password, String _transferType)
{
host = _host;
username = _username;
password = _password;

if ( !(_transferType.equals(BINARY)) && !(_transferType.equals(ASCII))
)
throw new RuntimeException("Illegal parameter for transferType");

transferType = _transferType;
}


/**
* Used to download a file from the ftp server's machine.
* @param filename - filename to read from the ftp server.
* @return StringBuffer - contents of the file from the ftp server.
*/
public StringBuffer downloadFile(String filename) throws IOException
{
return(downloadFile("",filename));
}

/**
* Used to download a file from the ftp server's machine.
* @param directory - directory which the file resides on the ftp
server.
* @param filename - filename to read from the ftp server.
* @return StringBuffer - contents of the file from the ftp server.
*/
public StringBuffer downloadFile(String dir, String filename)
throws IOException
{
if (!loggedIn)
login();

// cd to the proper directory
changeDirectory(dir);

// set transfer mode to either BINARY or ASCII
reply = doCommand("TYPE " + transferType);
checkResponse(reply,'2');

// get socket which to transport data over.
dataSocket = getDataSocket();
InputStream inputStream = dataSocket.getInputStream();

// issue command to start transmission of file.
doCommand("RETR " + filename);
checkResponse(reply,'1');

// retrieve data from server.
String contents = retrieveData(inputStream);

// close connection for data transfer
dataSocket.close();

reply = getResponse();
checkResponse(reply,'2');

return (new StringBuffer(contents));
}

/**
* Used internally to read data from given input stream when
transferring
* data from the ftp server.
*
* @param inputStream - InputStream from socket used to transfer data.
* @return String - contents read from the InputStream given.
*/
protected String retrieveData(InputStream inputStream)
throws IOException
{
int c = 0;
char lineBuffer[] = new char[128];
char buffer[] = lineBuffer;
int room = buffer.length;
int offset = 0;

try {
loop: while (true)
{
// read characters into buffer
switch (c = inputStream.read())
{
case -1: break loop;

default: if (--room < 0)
{
buffer = new char[offset+128];
room = buffer.length - offset - 1;
System.arraycopy(lineBuffer,0,buffer,0,offset);
lineBuffer = buffer;
buffer[offset++] = (char) c;
break;
}
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
throw new IOException("Problems encountered while reading" +
" file from Server");
}

if ((c == -1) && (offset == 0))
return null;

return String.copyValueOf(buffer,0,offset);
}

/**
* Used to write a file to the client system. NOTE: this will not work
* if the client is running as an Applet.
*
* @param filename - filename to write the contents to on the client
system.
* @param contents - contents of the file to write to the client file
system.
*/
public void writeFile(String filename, String contents) throws
IOException
{
RandomAccessFile raf = new RandomAccessFile(filename,"rw");
raf.writeBytes(contents);
}

/**
* Used internally to create the socket connection to the host system
and
* setup the input, output and print streams.
*
* @param hostname - hostname of the host running the ftp server.
* @param port - port to connect to on the host system. (usually port
21)
*/
protected void connect(String host, int port) throws IOException
{
try {
// create connection to ftp server.
sessionSocket = new Socket(host, port);
} catch (Exception e) {
throw new IOException("Unable to connect to host:\n" + host);
}

inStream = new DataInputStream(sessionSocket.getInputStream());
outStream = new DataOutputStream(sessionSocket.getOutputStream());
printStream = new PrintStream(outStream);

// get reply to validate conection.
reply = getResponse();
checkResponse(reply,'2');

loggedIn = true;
}

/**
* Used internally to send the login sequence to the host system via
socket.
*
* @param username - username to login to the ftp server.
* @param password - password to login to the ftp server.
*/
public void login() throws IOException
{
login(username, password);
}
/**
* Used internally to send the login sequence to the host system via
socket.
*
* @param username - username to login to the ftp server.
* @param password - password to login to the ftp server.
*/
public void login(String username, String password) throws IOException
{
this.username = username;
this.password = password;

if (!loggedIn)
connect(host,port);

// send username to ftp server to login
reply = doCommand("USER " + username);
checkResponse(reply,'3');

// send password to ftp server to login
reply = doCommand("PASS " + password);
checkResponse(reply,'2');
}

/**
* Used internally to send the logout sequence to the host system via
socket.
*/
public void logout() throws IOException {
// no response comes from here
printStream.println("QUIT");

try {
printStream.flush();
printStream.close();
outStream.close();
inStream.close();
sessionSocket.close();
dataSocket.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}

loggedIn = false;
}

/**
* Used internally to validate a response by the host system.
*/
protected void checkResponse(String response, char digit) throws
IOException
{
if (response.charAt(0) != digit)
throw new IOException(response);
}

/**
* Used internally to validate a response by the host system.
*
* @param command - command sent to the ftp server on the host system.
* @return String - reply received from the host system.
*/
protected String doCommand(String command) throws IOException
{
//System.out.println("doCommand: " + command);
printStream.println(command);
return (getResponse());
}

/**
* Used internally to retrieve a response from the host system.
* Watches for responses that also include line continuation
characters.
*
* @param command - command sent to the ftp server on the host system.
* @return String - reply received from the host system.
*/
protected String getResponse() throws IOException
{
while (true)
{
reply = inStream.readLine();

if (reply == null)
throw new IOException("Bad (null) response from server");

if (reply.length() < 3)
throw new IOException("Bad (short) response from server");

// If there isn't a dash ('-') immediately after the number, then
// we've gotten the complete response. (The dash is the continu
// ation character)

if ((reply.length() == 3) || (reply.charAt(3) != '-'))
break;
}
//System.out.println("getResponse: " + reply);
return (reply);
}

/**
* Used internally to retrieve a data connection from the host system.
* host ip address and port number are parsed from the server's reply
to
* generate information for data connection.
*
* @return Socket - socket used to retrieve data from ftp server.
*/
protected Socket getDataSocket() throws IOException
{
int ctr = 0;
Socket dataSocket = null;
String[] parts = new String[6];
String part = null;

// Switch to PASV mode, capture server reply for socket information
reply = doCommand("PASV");
checkResponse(reply,'2');

// Our reply has data with the host ip and port for retrieving/sending
// data. It is in the form of:
// ### Text (###,###,###,###,##,###)[.]
// where,
// ### - reply code starts with '2' is good
// Text - general status message
// (..###..) - is the ip address and port which to connect
// to for data transfer. 1st four #'s are the ip
// address and the last two #'s are the port.
// [.] - possible period at the end of the line.

BreakString bs = new BreakString(reply,",");
Enumeration e = bs.result();
while (e.hasMoreElements())
{
part = (String) e.nextElement();
if (part.endsWith(")."))
{
parts[ctr++] = part.substring(0,part.length()-2);
}
else if (part.endsWith(")"))
{
parts[ctr++] = part.substring(0,part.length()-1);
}
else if (part.lastIndexOf("(") >= 0)
{
int begin = part.lastIndexOf("(");
parts[ctr++] = part.substring(begin+1,part.length());
}
else
{
parts[ctr++] = part;
}
}
// Piece together the IP address.
String ip = parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3];

// Determine port
int port = -1;
try {
int big = Integer.parseInt(parts[4]) << 8;
int small = Integer.parseInt(parts[5]);
port = big + small; // port number
} catch(NumberFormatException nfe) {
nfe.printStackTrace();
}

if ((ip != null) && (port != -1))
{
try {
dataSocket = new Socket(ip, port);
} catch (Exception se) {
se.printStackTrace();
throw new IOException("Unable to connect to address/port");
}
}
else
throw new IOException("Invalid IP address or port received");

return dataSocket;
}

/**
* Used to change directories on the server side for data retrieval or
* transmission.
*
* @param dir - directory to change to on the ftp server.
*/
public void changeDirectory(String dir) throws IOException
{
// some ftp servers do not understand CWD without a dirname
if ((dir != null) && !(dir.equals("")) && !(dir.equals(" ")))
{
reply = doCommand("CWD " + dir);
checkResponse(reply,'2');
}
}

/**
* Used to show current working directory on the server side.
*/
public String showDirectory() throws IOException
{
String path = null;

reply = doCommand("PWD");
checkResponse(reply,'2');

try {
// The message is in the format of:
// ### "directory information" response information
BreakString bs = new BreakString(reply, "\"");
Enumeration e = bs.result();
e.nextElement(); // throw away first part
path = (String) e.nextElement(); // dir info
} catch (Exception e) {
throw new IOException("Badly formed response from server: \n" +
reply);
}
return path;
}

public void finalize() { try { logout(); } catch (Exception ignore) {}
}

/**
* Main entry point to test the operation of the ftp server.
*
* @param server - host server to transfer file to.
* @param username - username to login to the ftp server.
* @param password - password to login to the ftp server.
* @param filename - name of file to transfer to the server
* and back to client's system.
*/
public static void main(String[] args)
{
String usage = "USAGE: FTPSession server username passwd filename";
if (args.length < 4)
{
System.out.println("\n" + usage + "\n\n");
System.exit(0);
}

try {
FTPSession ftp = new FTPSession(args[0], args[1], args[2]);


// retieve list of files on server
String path = ftp.showDirectory();

// change directories on server
ftp.changeDirectory("..");

// change directories on server
ftp.changeDirectory(path);

// download file
System.out.println("Downloading File: new_" + args[3] + " .......");
StringBuffer sb = ftp.downloadFile(args[3]);
ftp.writeFile("new_"+args[3],sb.toString());

ftp.logout();

} catch(java.io.IOException ioe) {
ioe.printStackTrace();
}
}
}
 
G

Gordon Beaton

Through my client FTPSession.java, i am trying to download a file
from a ftp server which has a disclaimer on it. This disclaimer is a
multi line response.

The code of FTPSession, in its getResponse method is coded to handle
multi line responses, but when i connect to the server (it is a NT
server with Unix Style directory system) it gives me a null response
from the server. It gives me a error in the method "getResponse",
bad(short) response from the server.

Both kinds of errors can occur in that method. Which do you mean:
"null response" or "short response"?

Starting from the initial connection, exactly what does the entire
conversation with the server look like (what commands have you sent,
and what complete responses do you get) when this error occurs?

What happens when you connect to the server using telnet, and issue
the *exact* same set of commands manually?

You might also consider posting formatted code next time.

/gordon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top