package org.herac.tuxguitar.gui.tools.browser.ftp;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class TGBrowserFTPClient {
public static final int DEFAULT_PORT = 21;
public static final String DEFAULT_USER_NAME = "anonymous";
public static final String DEFAULT_USER_PASSWORD = "anonymous";
private static final String REQUEST_CD = "CWD";
private static final String REQUEST_CDUP = "CDUP";
private static final String REQUEST_EXIT = "QUIT";
private static final String REQUEST_GET = "RETR";
private static final String REQUEST_LIST_FILES = "LIST";
private static final String REQUEST_LIST_NAMES = "NLST";
private static final String REQUEST_PASSIVE = "PASV";
private static final String REQUEST_PWD = "PWD";
private static final String REQUEST_TYPE_ASCII = "TYPE A";
private static final String REQUEST_TYPE_BINARY = "TYPE I";
private static final String REQUEST_USER_NAME = "USER";
private static final String REQUEST_USER_PASSWORD = "PASS";
private static final int RESPONSE_CODE_CD = 250;
private static final int RESPONSE_CODE_CONNECT = 220;
private static final int RESPONSE_CODE_PASV = 227;
private static final int RESPONSE_CODE_PASV_CONNECTION = 150;
private static final int RESPONSE_CODE_PWD = 257;
private static final int RESPONSE_CODE_TYPE = 200;
private static final int RESPONSE_CODE_USER_NAME = 331;
private static final int RESPONSE_CODE_USER_PASSWORD = 230;
private static byte[] getByteBuffer(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read = 0;
while ((read = in.read()) != -1) {
out.write(read);
}
byte[] bytes = out.toByteArray();
out.close();
out.flush();
return bytes;
}
private boolean open;
private BufferedWriter request = null;
private BufferedReader response = null;
private Socket socket = null;
public synchronized boolean ascii() throws IOException {
this.setRequest(REQUEST_TYPE_ASCII);
return (getResponseError(RESPONSE_CODE_TYPE) == null);
}
public synchronized boolean binary() throws IOException {
this.setRequest(REQUEST_TYPE_BINARY);
return (getResponseError(RESPONSE_CODE_TYPE) == null);
}
public synchronized boolean cd(String dir) throws IOException {
this.setRequest(REQUEST_CD + " " + dir);
return (getResponseError(RESPONSE_CODE_CD) == null);
}
public synchronized boolean cdUp() throws IOException {
this.setRequest(REQUEST_CDUP);
return (getResponseError(RESPONSE_CODE_CD) == null);
}
public synchronized void close() throws IOException {
if (this.isOpen()) {
this.setRequest(REQUEST_EXIT);
this.socket.close();
this.socket = null;
}
this.setOpen(false);
}
public synchronized byte[] get(String file) throws IOException {
return sendPasvCMD(REQUEST_GET + " " + file);
}
private String getResponse() throws IOException {
return this.response.readLine();
}
private String getResponse(int expectedCode) throws IOException {
String response = this.getResponse();
// Some FTP Servers appends comments like "[CODE_NUMBER]-".
// This while tries to skip all comments before response.
while (response != null && response.indexOf(expectedCode + "-") == 0) {
response = this.getResponse();
}
return response;
}
private String getResponseError(int expectedCode) throws IOException {
String response = getResponse(expectedCode);
return (isExpectedResponse(response, expectedCode) ? null : response);
}
private boolean isExpectedResponse(String response, int expectedCode) {
return (response != null && response.indexOf(expectedCode + " ") == 0);
}
public boolean isOpen() {
return this.open;
}
public synchronized String[] listDetails() throws IOException {
return new String(sendPasvCMD(REQUEST_LIST_FILES)).split("\r\n");
}
public synchronized String[] listNames() throws IOException {
return new String(sendPasvCMD(REQUEST_LIST_NAMES)).split("\r\n");
}
public synchronized void login(String user, String password)
throws IOException {
String error = null;
this.setRequest(REQUEST_USER_NAME + " " + user);
if ((error = getResponseError(RESPONSE_CODE_USER_NAME)) != null) {
throw new IOException(error);
}
this.setRequest(REQUEST_USER_PASSWORD + " " + password);
if ((error = getResponseError(RESPONSE_CODE_USER_PASSWORD)) != null) {
throw new IOException(error);
}
}
public synchronized void open(String host, int port) throws IOException {
this.socket = new Socket(host, port);
this.response = new BufferedReader(new InputStreamReader(this.socket
.getInputStream()));
this.request = new BufferedWriter(new OutputStreamWriter(this.socket
.getOutputStream()));
String response = getResponse(RESPONSE_CODE_CONNECT);
if (!isExpectedResponse(response, RESPONSE_CODE_CONNECT)) {
throw new IOException(response);
}
this.setOpen(true);
}
public synchronized String pwd() throws IOException {
this.setRequest(REQUEST_PWD);
String response = getResponse(RESPONSE_CODE_PWD);
if (isExpectedResponse(response, RESPONSE_CODE_PWD)) {
int i1 = response.indexOf('\"');
int i2 = response.indexOf('\"', i1 + 1);
if (i2 > i1) {
return response.substring(i1 + 1, i2);
}
}
return null;
}
private synchronized byte[] sendPasvCMD(String cmd) throws IOException {
byte[] buffer = new byte[0];
setRequest(REQUEST_PASSIVE);
String response = getResponse(RESPONSE_CODE_PASV);
if (isExpectedResponse(response, RESPONSE_CODE_PASV)) {
setRequest(cmd);
int addressIndex1 = response.indexOf("(") + 1;
int addressIndex2 = response.indexOf(")");
if (addressIndex1 > 0 && addressIndex2 > addressIndex1) {
String[] address = response.substring(addressIndex1, addressIndex2)
.split(",");
if (address.length == 6) {
int a1 = Integer.parseInt(address[0]);
int a2 = Integer.parseInt(address[1]);
int a3 = Integer.parseInt(address[2]);
int a4 = Integer.parseInt(address[3]);
int p1 = Integer.parseInt(address[4]);
int p2 = Integer.parseInt(address[5]);
Socket socket = new Socket((a1 + "." + a2 + "." + a3 + "." + a4),
((p1 * 256) + p2));
response = getResponse(RESPONSE_CODE_PASV_CONNECTION);
if (isExpectedResponse(response, RESPONSE_CODE_PASV_CONNECTION)) {
buffer = getByteBuffer(socket.getInputStream());
}
socket.close();
}
}
if (isExpectedResponse(response, RESPONSE_CODE_PASV_CONNECTION)) {
response = getResponse();
}
}
return buffer;
}
public void setOpen(boolean open) {
this.open = open;
}
private void setRequest(String line) throws IOException {
this.request.write(line + "\r\n");
this.request.flush();
}
}