/************************************************************************** * Copyright (c) 2001 by Punch Telematix. All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix nor the names of * * other contributors may be used to endorse or promote products * * derived from this software without specific prior written permission.* * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX OR OTHER CONTRIBUTORS BE LIABLE * * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ package wonka.net.ftp; import java.io.IOException; import java.io.InputStream; import java.io.DataInputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketPermission; import java.net.URL; import java.net.URLConnection; import java.security.Permission; public class FtpURLConnection extends URLConnection { private static int clientport = 64000; private static final byte[] USER_BYTES = "USER ftp\r\n".getBytes(); private static final byte[] PASS_BYTES = "PASS wonka\r\n".getBytes(); private static final byte[] PORT_BYTES = "PORT ".getBytes(); private static final byte[] RETR_BYTES = "RETR ".getBytes(); private static final byte[] QUIT_BYTES = "QUIT \r\n".getBytes(); private static final byte[] CRLF = {13,10}; private Socket control; private ServerSocket acceptor; private Socket datastream; public FtpURLConnection(URL url) { super(url); } public synchronized void connect() throws IOException { if(!connected){ int port = url.getPort(); if(port == -1){ port = 21; } control = new Socket(url.getHost(),port); control.setSoTimeout(5000); if(clientport < 1025){ clientport = 64000; } port = clientport; while (true){ try { acceptor = new ServerSocket(port); clientport = port - 1; break; } catch(IOException ioe){ if(port < 1025){ port = 65000; } else { port--; } } } OutputStream out = control.getOutputStream(); DataInputStream in = new DataInputStream(control.getInputStream()); String code = checkReply(in); if(!code.equals("220")){ closeWithException("ftp service is unavailable"); } out.write(USER_BYTES); code = checkReply(in); if(code.equals("331")){ out.write(PASS_BYTES); code = checkReply(in); if(!code.equals("230") && !code.equals("202")){ closeWithException("Password needed to login on "+url.getHost()+" as user ftp"); } } else if(!code.equals("230")){ closeWithException("Unable to login on "+url.getHost()+" as user ftp"); } out.write("TYPE I\r\n".getBytes()); code = checkReply(in); if(!code.equals("200") && !code.equals("502")){ closeWithException("Failed to set type"); } out.write(PORT_BYTES); out.write(writePort(InetAddress.getLocalHost().getAddress(),port)); out.write(CRLF); code = checkReply(in); if(!code.equals("200")){ closeWithException("Failed to specify port"); } out.write(RETR_BYTES); out.write(url.getFile().getBytes()); out.write(CRLF); code = checkReply(in); if(!code.equals("150") && !code.equals("125")){ closeWithException("RETR request failed for "+url.getFile()); } acceptor.setSoTimeout(5000); datastream = acceptor.accept(); connected = true; } } public Permission getPermission() throws IOException { return new SocketPermission(url.getHost()+":"+(url.getPort()== -1 ? 21 : url.getPort()) , "connect"); } public InputStream getInputStream() throws IOException { if (!connected) { connect(); } return datastream.getInputStream(); } private byte[] writePort(byte[] address, int port) throws IOException { StringBuffer buf = new StringBuffer(128); for(int i = 0 ; i < address.length ; i++){ buf.append((0xff &(char)address[i])); buf.append(','); } buf.append(port>>8); buf.append(','); buf.append(port & 0xff); return buf.toString().getBytes(); } private String checkReply(DataInputStream in) throws IOException { String reply = null; do { reply = in.readLine(); if(reply == null || reply.length() < 3){ control.getOutputStream().write(QUIT_BYTES); control.close(); throw new IOException("Invalid Response"); } if(reply.length() == 3){ break; } //System.out.println(reply); } while(reply.charAt(3) == '-'); //System.out.println("RETURNING REPLY CODE "+reply.substring(0,3)); return reply.substring(0,3); } private void closeWithException(String message) throws IOException { control.getOutputStream().write(QUIT_BYTES); control.close(); throw new IOException(message); } }