diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/gnu/java/net/protocol/ftp | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/gnu/java/net/protocol/ftp')
17 files changed, 3634 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java new file mode 100644 index 000000000..1ed31b830 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java @@ -0,0 +1,251 @@ +/* ActiveModeDTP.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * An active mode FTP data transfer process. + * This starts a server on the specified port listening for a data + * connection. It converts the socket input into a file stream for reading. + * + * @author Chris Burdess (dog@gnu.org) + */ +final class ActiveModeDTP + implements DTP, Runnable +{ + + ServerSocket server; + Socket socket; + DTPInputStream in; + DTPOutputStream out; + boolean completed; + boolean inProgress; + int transferMode; + IOException exception; + Thread acceptThread; + int connectionTimeout; + + ActiveModeDTP(InetAddress localhost, int port, + int connectionTimeout, int timeout) + throws IOException + { + completed = false; + inProgress = false; + server = new ServerSocket(port, 1, localhost); + if (timeout > 0) + { + server.setSoTimeout(timeout); + } + if (connectionTimeout <= 0) + { + connectionTimeout = 20000; + } + this.connectionTimeout = connectionTimeout; + acceptThread = new Thread(this, "ActiveModeDTP"); + acceptThread.setDaemon(true); + acceptThread.start(); + } + + /** + * Start listening. + */ + public void run() + { + try + { + socket = server.accept(); + //System.err.println("Accepted connection from "+socket.getInetAddress()+":"+socket.getPort()); + } + catch (IOException e) + { + exception = e; + } + } + + /** + * Waits until a client has connected. + */ + public void waitFor() + throws IOException + { + try + { + acceptThread.join(connectionTimeout); + } + catch (InterruptedException e) + { + } + if (exception != null) + { + throw exception; + } + if (socket == null) + { + server.close(); + throw new IOException("client did not connect before timeout"); + } + acceptThread = null; + } + + /** + * Returns an input stream from which a remote file can be read. + */ + public InputStream getInputStream() + throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + if (acceptThread != null) + { + waitFor(); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + in = new StreamInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_BLOCK: + in = new BlockInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + in = new CompressedInputStream(this, socket.getInputStream()); + break; + default: + throw new IllegalStateException("invalid transfer mode"); + } + in.setTransferComplete(false); + return in; + } + + /** + * Returns an output stream to which a local file can be written for + * upload. + */ + public OutputStream getOutputStream() throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + if (acceptThread != null) + { + waitFor(); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + out = new StreamOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_BLOCK: + out = new BlockOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + out = new CompressedOutputStream(this, socket.getOutputStream()); + break; + default: + throw new IllegalStateException("invalid transfer mode"); + } + out.setTransferComplete(false); + return out; + } + + public void setTransferMode(int mode) + { + transferMode = mode; + } + + public void complete() + { + completed = true; + if (!inProgress) + { + transferComplete(); + } + } + + public boolean abort() + { + completed = true; + transferComplete(); + return inProgress; + } + + public void transferComplete() + { + if (socket == null) + { + return; + } + if (in != null) + { + in.setTransferComplete(true); + } + if (out != null) + { + out.setTransferComplete(true); + } + completed = completed || (transferMode == FTPConnection.MODE_STREAM); + if (completed && socket != null) + { + try + { + socket.close(); + } + catch (IOException e) + { + } + try + { + server.close(); + } + catch (IOException e) + { + } + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java new file mode 100644 index 000000000..09915e7ff --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java @@ -0,0 +1,149 @@ +/* BlockInputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A DTP input stream that implements the FTP block transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class BlockInputStream + extends DTPInputStream +{ + + static final int EOF = 64; + + int descriptor; + int max = -1; + int count = -1; + + BlockInputStream(DTP dtp, InputStream in) + { + super(dtp, in); + } + + public int read() + throws IOException + { + if (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + int c = in.read(); + if (c == -1) + { + dtp.transferComplete(); + } + count++; + if (count >= max) + { + count = -1; + if (descriptor == EOF) + { + close(); + } + } + return c; + } + + public int read(byte[] buf) + throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + if (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + int l = in.read(buf, off, len); + if (l == -1) + { + dtp.transferComplete(); + } + count += l; + if (count >= max) + { + count = -1; + if (descriptor == EOF) + { + close(); + } + } + return l; + } + + /** + * Reads the block header. + */ + void readHeader() + throws IOException + { + descriptor = in.read(); + int max_hi = in.read(); + int max_lo = in.read(); + max = (max_hi << 8) | max_lo; + count = 0; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java new file mode 100644 index 000000000..d181f9dec --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java @@ -0,0 +1,110 @@ +/* BlockOutputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A DTP output stream that implements the FTP block transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class BlockOutputStream + extends DTPOutputStream +{ + + static final byte RECORD = -128; // 0x80 + static final byte EOF = 64; // 0x40 + + BlockOutputStream(DTP dtp, OutputStream out) + { + super(dtp, out); + } + + public void write(int c) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = new byte[] + { + RECORD, /* record descriptor */ + 0x00, 0x01, /* one byte */ + (byte) c /* the byte */ + }; + out.write(buf, 0, 4); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = new byte[len + 3]; + buf[0] = RECORD; /* record descriptor */ + buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */ + buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */ + System.arraycopy(b, off, buf, 3, len); + out.write(buf, 0, len); + } + + public void close() + throws IOException + { + byte[] buf = new byte[] + { + EOF, /* eof descriptor */ + 0x00, 0x00 /* no bytes */ + }; + out.write(buf, 0, 3); + super.close(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java new file mode 100644 index 000000000..638d780e6 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java @@ -0,0 +1,214 @@ +/* CompressedInputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; + +/** + * A DTP input stream that implements the FTP compressed transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class CompressedInputStream + extends DTPInputStream +{ + + static final int EOF = 64; + + static final int RAW = 0x00; + static final int COMPRESSED = 0x80; + static final int FILLER = 0xc0; + + int descriptor; + int max = -1; + int count = -1; + + int state = RAW; // RAW | STATE | FILLER + int rep; // the compressed byte + int n = 0; // the number of compressed or raw bytes + + CompressedInputStream(DTP dtp, InputStream in) + { + super(dtp, in); + } + + public int read() + throws IOException + { + if (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + if (n > 0 && (state == COMPRESSED || state == FILLER)) + { + n--; + return rep; + } + int c = in.read(); + if (c == -1) + { + close(); + } + count++; + if (count >= max) + { + count = -1; + if (descriptor == EOF) + { + close(); + } + } + if (c == -1) + { + return c; + } + while (n == 0) // read code header + { + state = (c & 0xc0); + n = (c & 0x3f); + c = in.read(); + if (c == -1) + { + return -1; + } + } + switch (state) + { + case RAW: + break; + case COMPRESSED: + case FILLER: + rep = c; + break; + default: + throw new ProtocolException("Illegal state: " + state); + } + n--; + return c; + } + + public int read(byte[] buf) + throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + if (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + // TODO improve performance + for (int i = off; i < len; i++) + { + int c = read(); + if (c == -1) + { + close(); + return i; + } + buf[i] = (byte) c; + } + return len; + /* + int l = in.read (buf, off, len); + if (l==-1) + { + close (); + } + count += l; + if (count>=max) + { + count = -1; + if (descriptor==EOF) + { + close (); + } + } + return l; + */ + } + + /** + * Reads the block header. + */ + void readHeader() + throws IOException + { + descriptor = in.read(); + int max_hi = in.read(); + int max_lo = in.read(); + max = (max_hi << 8) | max_lo; + count = 0; + } + + /** + * Reads the code header. + */ + void readCodeHeader() + throws IOException + { + int code = in.read(); + state = (code & 0xc0); + n = (code & 0x3f); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java new file mode 100644 index 000000000..ec3aef930 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java @@ -0,0 +1,227 @@ +/* CompressedOutputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A DTP output stream that implements the FTP compressed transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class CompressedOutputStream + extends DTPOutputStream +{ + + static final byte RECORD = -128; // 0x80 + static final byte EOF = 64; // 0x40 + + CompressedOutputStream(DTP dtp, OutputStream out) + { + super(dtp, out); + } + + /** + * Just one byte cannot be compressed. + * It takes 5 bytes to transmit - hardly very compressed! + */ + public void write(int c) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = new byte[] + { + RECORD, /* record descriptor */ + 0x00, 0x01, /* one byte */ + 0x01, /* one uncompressed byte */ + (byte) c /* the byte */ + }; + out.write(buf, 0, 5); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + /** + * The larger len is, the better. + */ + public void write(byte[] b, int off, int len) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = compress(b, off, len); + len = buf.length; + buf[0] = RECORD; /* record descriptor */ + buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */ + buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */ + out.write(buf, 0, len); + } + + /** + * Returns the compressed form of the given byte array. + * The first 3 bytes are left free for header information. + */ + byte[] compress(byte[] b, int off, int len) + { + byte[] buf = new byte[len]; + byte last = 0; + int pos = 0, raw_count = 0, rep_count = 1; + for (int i = off; i < len; i++) + { + byte c = b[i]; + if (i > off && c == last) // compress + { + if (raw_count > 0) // flush raw bytes to buf + { + // need to add raw_count+1 bytes + if (pos + (raw_count + 1) > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_raw(buf, pos, b, (i - raw_count) - 1, + raw_count); + raw_count = 0; + } + rep_count++; // keep looking for same byte + } + else + { + if (rep_count > 1) // flush compressed bytes to buf + { + // need to add 2 bytes + if (pos + 2 > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_compressed(buf, pos, rep_count, last); + rep_count = 1; + } + raw_count++; // keep looking for raw bytes + } + if (rep_count == 127) // flush compressed bytes + { + // need to add 2 bytes + if (pos + 2 > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_compressed(buf, pos, rep_count, last); + rep_count = 1; + } + if (raw_count == 127) // flush raw bytes + { + // need to add raw_count+1 bytes + if (pos + (raw_count + 1) > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_raw(buf, pos, b, (i - raw_count), raw_count); + raw_count = 0; + } + last = c; + } + if (rep_count > 1) // flush compressed bytes + { + // need to add 2 bytes + if (pos + 2 > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_compressed(buf, pos, rep_count, last); + rep_count = 1; + } + if (raw_count > 0) // flush raw bytes + { + // need to add raw_count+1 bytes + if (pos + (raw_count + 1) > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_raw(buf, pos, b, (len - raw_count), raw_count); + raw_count = 0; + } + byte[] ret = new byte[pos + 3]; + System.arraycopy(buf, 0, ret, 3, pos); + return ret; + } + + int flush_compressed(byte[] buf, int pos, int count, byte c) + { + buf[pos++] = (byte) (0x80 | count); + buf[pos++] = c; + return pos; + } + + int flush_raw(byte[] buf, int pos, byte[] src, int off, int len) + { + buf[pos++] = (byte) len; + System.arraycopy(src, off, buf, pos, len); + return pos + len; + } + + byte[] realloc(byte[] buf, int len) + { + byte[] ret = new byte[buf.length + len]; + System.arraycopy(buf, 0, ret, 0, buf.length); + return ret; + } + + public void close() + throws IOException + { + byte[] buf = new byte[] + { + EOF, /* eof descriptor */ + 0x00, 0x00 /* no bytes */ + }; + out.write(buf, 0, 3); + out.close(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java new file mode 100644 index 000000000..9ba4b7c6c --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java @@ -0,0 +1,91 @@ +/* DTP.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * An FTP data transfer process. + * + * @author Chris Burdess (dog@gnu.org) + */ +interface DTP +{ + + /** + * Returns an input stream from which a remote file can be read. + */ + InputStream getInputStream() + throws IOException; + + /** + * Returns an output stream to which a local file can be written for + * upload. + */ + OutputStream getOutputStream() + throws IOException; + + /** + * Sets the transfer mode to be used with this DTP. + */ + void setTransferMode(int mode); + + /** + * Marks this DTP completed. + * When the current transfer has finished, any resources will be released. + */ + void complete(); + + /** + * Aborts any current transfer and releases all resources held by this + * DTP. + * @return true if a transfer was interrupted, false otherwise + */ + boolean abort(); + + /** + * Used to notify the DTP that its current transfer is complete. + * This occurs either when end-of-stream is reached or a 226 response is + * received. + */ + void transferComplete(); + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java new file mode 100644 index 000000000..7280b0133 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java @@ -0,0 +1,87 @@ +/* DTPInputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * An input stream that notifies a DTP on completion. + * + * @author Chris Burdess (dog@gnu.org) + */ +abstract class DTPInputStream + extends FilterInputStream +{ + + DTP dtp; + boolean transferComplete; + + /** + * Constructor. + * @param dtp the controlling data transfer process + * @param in the underlying socket stream + */ + DTPInputStream (DTP dtp, InputStream in) + { + super(in); + this.dtp = dtp; + transferComplete = false; + } + + /** + * Marks this input stream complete. + * This is called by the DTP. + */ + void setTransferComplete(boolean flag) + { + transferComplete = flag; + } + + /** + * Notifies the controlling DTP that this stream has completed transfer. + */ + public void close() + throws IOException + { + dtp.transferComplete(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java new file mode 100644 index 000000000..105c6f095 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java @@ -0,0 +1,85 @@ +/* DTPOutputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An output stream that notifies a DTP on end of stream. + * + * @author Chris Burdess (dog@gnu.org) + */ +abstract class DTPOutputStream extends FilterOutputStream +{ + + DTP dtp; + boolean transferComplete; + + /** + * Constructor. + * @param dtp the controlling data transfer process + * @param out the socket output stream + */ + DTPOutputStream (DTP dtp, OutputStream out) + { + super (out); + this.dtp = dtp; + transferComplete = false; + } + + /** + * Tells this stream whether transfer has completed or not. + * @param flag true if the process has completed, false otherwise + */ + void setTransferComplete (boolean flag) + { + transferComplete = flag; + } + + /** + * Notifies the controlling DTP that this stream has been terminated. + */ + public void close () throws IOException + { + dtp.transferComplete (); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java new file mode 100644 index 000000000..4e253fcb9 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java @@ -0,0 +1,1352 @@ +/* FTPConnection.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.net.CRLFInputStream; +import gnu.java.net.CRLFOutputStream; +import gnu.java.net.EmptyX509TrustManager; +import gnu.java.net.LineInputStream; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolException; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +/** + * An FTP client connection, or PI. + * This implements RFC 959, with the following exceptions: + * <ul> + * <li>STAT, HELP, SITE, SMNT, and ACCT commands are not supported.</li> + * <li>the TYPE command does not allow alternatives to the default bytesize + * (Non-print), and local bytesize is not supported.</li> + * </ul> + * + * @author Chris Burdess (dog@gnu.org) + */ +public class FTPConnection +{ + + /** + * The default FTP transmission control port. + */ + public static final int FTP_PORT = 21; + + /** + * The FTP data port. + */ + public static final int FTP_DATA_PORT = 20; + + // -- FTP vocabulary -- + protected static final String USER = "USER"; + protected static final String PASS = "PASS"; + protected static final String ACCT = "ACCT"; + protected static final String CWD = "CWD"; + protected static final String CDUP = "CDUP"; + protected static final String SMNT = "SMNT"; + protected static final String REIN = "REIN"; + protected static final String QUIT = "QUIT"; + + protected static final String PORT = "PORT"; + protected static final String PASV = "PASV"; + protected static final String TYPE = "TYPE"; + protected static final String STRU = "STRU"; + protected static final String MODE = "MODE"; + + protected static final String RETR = "RETR"; + protected static final String STOR = "STOR"; + protected static final String STOU = "STOU"; + protected static final String APPE = "APPE"; + protected static final String ALLO = "ALLO"; + protected static final String REST = "REST"; + protected static final String RNFR = "RNFR"; + protected static final String RNTO = "RNTO"; + protected static final String ABOR = "ABOR"; + protected static final String DELE = "DELE"; + protected static final String RMD = "RMD"; + protected static final String MKD = "MKD"; + protected static final String PWD = "PWD"; + protected static final String LIST = "LIST"; + protected static final String NLST = "NLST"; + protected static final String SITE = "SITE"; + protected static final String SYST = "SYST"; + protected static final String STAT = "STAT"; + protected static final String HELP = "HELP"; + protected static final String NOOP = "NOOP"; + + protected static final String AUTH = "AUTH"; + protected static final String PBSZ = "PBSZ"; + protected static final String PROT = "PROT"; + protected static final String CCC = "CCC"; + protected static final String TLS = "TLS"; + + public static final int TYPE_ASCII = 1; + public static final int TYPE_EBCDIC = 2; + public static final int TYPE_BINARY = 3; + + public static final int STRUCTURE_FILE = 1; + public static final int STRUCTURE_RECORD = 2; + public static final int STRUCTURE_PAGE = 3; + + public static final int MODE_STREAM = 1; + public static final int MODE_BLOCK = 2; + public static final int MODE_COMPRESSED = 3; + + // -- Telnet constants -- + private static final String US_ASCII = "US-ASCII"; + + /** + * The socket used to communicate with the server. + */ + protected Socket socket; + + /** + * The socket input stream. + */ + protected LineInputStream in; + + /** + * The socket output stream. + */ + protected CRLFOutputStream out; + + /** + * The timeout when attempting to connect a socket. + */ + protected int connectionTimeout; + + /** + * The read timeout on sockets. + */ + protected int timeout; + + /** + * If true, print debugging information. + */ + protected boolean debug; + + /** + * The current data transfer process in use by this connection. + */ + protected DTP dtp; + + /** + * The current representation type. + */ + protected int representationType = TYPE_ASCII; + + /** + * The current file structure type. + */ + protected int fileStructure = STRUCTURE_FILE; + + /** + * The current transfer mode. + */ + protected int transferMode = MODE_STREAM; + + /** + * If true, use passive mode. + */ + protected boolean passive = false; + + /** + * Creates a new connection to the server using the default port. + * @param hostname the hostname of the server to connect to + */ + public FTPConnection(String hostname) + throws UnknownHostException, IOException + { + this(hostname, -1, 0, 0, false); + } + + /** + * Creates a new connection to the server. + * @param hostname the hostname of the server to connect to + * @param port the port to connect to(if <=0, use default port) + */ + public FTPConnection(String hostname, int port) + throws UnknownHostException, IOException + { + this(hostname, port, 0, 0, false); + } + + /** + * Creates a new connection to the server. + * @param hostname the hostname of the server to connect to + * @param port the port to connect to(if <=0, use default port) + * @param connectionTimeout the connection timeout, in milliseconds + * @param timeout the I/O timeout, in milliseconds + * @param debug print debugging information + */ + public FTPConnection(String hostname, int port, + int connectionTimeout, int timeout, boolean debug) + throws UnknownHostException, IOException + { + this.connectionTimeout = connectionTimeout; + this.timeout = timeout; + this.debug = debug; + if (port <= 0) + { + port = FTP_PORT; + } + + // Set up socket + socket = new Socket(); + InetSocketAddress address = new InetSocketAddress(hostname, port); + if (connectionTimeout > 0) + { + socket.connect(address, connectionTimeout); + } + else + { + socket.connect(address); + } + if (timeout > 0) + { + socket.setSoTimeout(timeout); + } + + InputStream in = socket.getInputStream(); + in = new BufferedInputStream(in); + in = new CRLFInputStream(in); + this.in = new LineInputStream(in); + OutputStream out = socket.getOutputStream(); + out = new BufferedOutputStream(out); + this.out = new CRLFOutputStream(out); + + // Read greeting + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 220: // hello + break; + default: + throw new FTPException(response); + } + } + + /** + * Authenticate using the specified username and password. + * If the username suffices for the server, the password will not be used + * and may be null. + * @param username the username + * @param password the optional password + * @return true on success, false otherwise + */ + public boolean authenticate(String username, String password) + throws IOException + { + String cmd = USER + ' ' + username; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 230: // User logged in + return true; + case 331: // User name okay, need password + break; + case 332: // Need account for login + case 530: // No such user + return false; + default: + throw new FTPException(response); + } + cmd = PASS + ' ' + password; + send(cmd); + response = getResponse(); + switch (response.getCode()) + { + case 230: // User logged in + case 202: // Superfluous + return true; + case 332: // Need account for login + case 530: // Bad password + return false; + default: + throw new FTPException(response); + } + } + + /** + * Negotiates TLS over the current connection. + * See IETF draft-murray-auth-ftp-ssl-15.txt for details. + * @param confidential whether to provide confidentiality for the + * connection + */ + public boolean starttls(boolean confidential) + throws IOException + { + return starttls(confidential, new EmptyX509TrustManager()); + } + + /** + * Negotiates TLS over the current connection. + * See IETF draft-murray-auth-ftp-ssl-15.txt for details. + * @param confidential whether to provide confidentiality for the + * connection + * @param tm the trust manager used to validate the server certificate. + */ + public boolean starttls(boolean confidential, TrustManager tm) + throws IOException + { + try + { + // Use SSLSocketFactory to negotiate a TLS session and wrap the + // current socket. + SSLContext context = SSLContext.getInstance("TLS"); + // We don't require strong validation of the server certificate + TrustManager[] trust = new TrustManager[] { tm }; + context.init(null, trust, null); + SSLSocketFactory factory = context.getSocketFactory(); + + send(AUTH + ' ' + TLS); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 500: + case 502: + case 504: + case 534: + case 431: + return false; + case 234: + break; + default: + throw new FTPException(response); + } + + String hostname = socket.getInetAddress().getHostName(); + int port = socket.getPort(); + SSLSocket ss = + (SSLSocket) factory.createSocket(socket, hostname, port, true); + String[] protocols = { "TLSv1", "SSLv3" }; + ss.setEnabledProtocols(protocols); + ss.setUseClientMode(true); + ss.startHandshake(); + + // PBSZ:PROT sequence + send(PBSZ + ' ' + Integer.MAX_VALUE); + response = getResponse(); + switch (response.getCode()) + { + case 501: // syntax error + case 503: // not authenticated + return false; + case 200: + break; + default: + throw new FTPException(response); + } + send(PROT + ' ' +(confidential ? 'P' : 'C')); + response = getResponse(); + switch (response.getCode()) + { + case 503: // not authenticated + case 504: // invalid level + case 536: // level not supported + return false; + case 200: + break; + default: + throw new FTPException(response); + } + + if (confidential) + { + // Set up streams + InputStream in = ss.getInputStream(); + in = new BufferedInputStream(in); + in = new CRLFInputStream(in); + this.in = new LineInputStream(in); + OutputStream out = ss.getOutputStream(); + out = new BufferedOutputStream(out); + this.out = new CRLFOutputStream(out); + } + return true; + } + catch (GeneralSecurityException e) + { + return false; + } + } + + /** + * Changes directory to the specified path. + * @param path an absolute or relative pathname + * @return true on success, false if the specified path does not exist + */ + public boolean changeWorkingDirectory(String path) + throws IOException + { + // Do nothing if the path is empty. + if (path.length() == 0) + return true; + String cmd = CWD + ' ' + path; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: + return true; + case 550: + return false; + default: + throw new FTPException(response); + } + } + + /** + * Changes directory to the parent of the current working directory. + * @return true on success, false otherwise + */ + public boolean changeToParentDirectory() + throws IOException + { + send(CDUP); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: + return true; + case 550: + return false; + default: + throw new FTPException(response); + } + } + + /** + * Terminates an authenticated login. + * If file transfer is in progress, it remains active for result response + * only. + */ + public void reinitialize() + throws IOException + { + send(REIN); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 220: + if (dtp != null) + { + dtp.complete(); + dtp = null; + } + break; + default: + throw new FTPException(response); + } + } + + /** + * Terminates the control connection. + * The file transfer connection remains open for result response only. + * This connection is invalid and no further commands may be issued. + */ + public void logout() + throws IOException + { + send(QUIT); + try + { + getResponse(); // not required + } + catch (IOException e) + { + } + if (dtp != null) + { + dtp.complete(); + dtp = null; + } + try + { + socket.close(); + } + catch (IOException e) + { + } + } + + /** + * Initialise the data transfer process. + */ + protected void initialiseDTP() + throws IOException + { + if (dtp != null) + { + dtp.complete(); + dtp = null; + } + + InetAddress localhost = socket.getLocalAddress(); + if (passive) + { + send(PASV); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 227: + String message = response.getMessage(); + try + { + int start = message.indexOf(','); + char c = message.charAt(start - 1); + while (c >= 0x30 && c <= 0x39) + { + c = message.charAt((--start) - 1); + } + int mid1 = start; + for (int i = 0; i < 4; i++) + { + mid1 = message.indexOf(',', mid1 + 1); + } + int mid2 = message.indexOf(',', mid1 + 1); + if (mid1 == -1 || mid2 < mid1) + { + throw new ProtocolException("Malformed 227: " + + message); + } + int end = mid2; + c = message.charAt(end + 1); + while (c >= 0x30 && c <= 0x39) + { + c = message.charAt((++end) + 1); + } + + String address = + message.substring(start, mid1).replace(',', '.'); + int port_hi = + Integer.parseInt(message.substring(mid1 + 1, mid2)); + int port_lo = + Integer.parseInt(message.substring(mid2 + 1, end + 1)); + int port = (port_hi << 8) | port_lo; + + /*System.out.println("Entering passive mode: " + address + + ":" + port);*/ + dtp = new PassiveModeDTP(address, port, localhost, + connectionTimeout, timeout); + break; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new ProtocolException(e.getMessage() + ": " + + message); + } + catch (NumberFormatException e) + { + throw new ProtocolException(e.getMessage() + ": " + + message); + } + default: + throw new FTPException(response); + } + } + else + { + // Get the local port + int port = socket.getLocalPort() + 1; + int tries = 0; + // Bind the active mode DTP + while (dtp == null) + { + try + { + dtp = new ActiveModeDTP(localhost, port, + connectionTimeout, timeout); + /*System.out.println("Listening on: " + port);*/ + } + catch (BindException e) + { + port++; + tries++; + if (tries > 9) + { + throw e; + } + } + } + + // Send PORT command + CPStringBuilder buf = new CPStringBuilder(PORT); + buf.append(' '); + // Construct the address/port string form + byte[] address = localhost.getAddress(); + for (int i = 0; i < address.length; i++) + { + int a =(int) address[i]; + if (a < 0) + { + a += 0x100; + } + buf.append(a); + buf.append(','); + } + int port_hi =(port & 0xff00) >> 8; + int port_lo =(port & 0x00ff); + buf.append(port_hi); + buf.append(','); + buf.append(port_lo); + send(buf.toString()); + // Get response + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: // OK + break; + default: + dtp.abort(); + dtp = null; + throw new FTPException(response); + } + } + dtp.setTransferMode(transferMode); + } + + /** + * Set passive mode. + * @param flag true if we should use passive mode, false otherwise + */ + public void setPassive(boolean flag) + throws IOException + { + if (passive != flag) + { + passive = flag; + initialiseDTP(); + } + } + + /** + * Returns the current representation type of the transfer data. + * @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY + */ + public int getRepresentationType() + { + return representationType; + } + + /** + * Sets the desired representation type of the transfer data. + * @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY + */ + public void setRepresentationType(int type) + throws IOException + { + CPStringBuilder buf = new CPStringBuilder(TYPE); + buf.append(' '); + switch (type) + { + case TYPE_ASCII: + buf.append('A'); + break; + case TYPE_EBCDIC: + buf.append('E'); + break; + case TYPE_BINARY: + buf.append('I'); + break; + default: + throw new IllegalArgumentException(Integer.toString(type)); + } + //buf.append(' '); + //buf.append('N'); + send(buf.toString()); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + representationType = type; + break; + default: + throw new FTPException(response); + } + } + + /** + * Returns the current file structure type. + * @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE + */ + public int getFileStructure() + { + return fileStructure; + } + + /** + * Sets the desired file structure type. + * @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE + */ + public void setFileStructure(int structure) + throws IOException + { + CPStringBuilder buf = new CPStringBuilder(STRU); + buf.append(' '); + switch (structure) + { + case STRUCTURE_FILE: + buf.append('F'); + break; + case STRUCTURE_RECORD: + buf.append('R'); + break; + case STRUCTURE_PAGE: + buf.append('P'); + break; + default: + throw new IllegalArgumentException(Integer.toString(structure)); + } + send(buf.toString()); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + fileStructure = structure; + break; + default: + throw new FTPException(response); + } + } + + /** + * Returns the current transfer mode. + * @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED + */ + public int getTransferMode() + { + return transferMode; + } + + /** + * Sets the desired transfer mode. + * @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED + */ + public void setTransferMode(int mode) + throws IOException + { + CPStringBuilder buf = new CPStringBuilder(MODE); + buf.append(' '); + switch (mode) + { + case MODE_STREAM: + buf.append('S'); + break; + case MODE_BLOCK: + buf.append('B'); + break; + case MODE_COMPRESSED: + buf.append('C'); + break; + default: + throw new IllegalArgumentException(Integer.toString(mode)); + } + send(buf.toString()); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + transferMode = mode; + if (dtp != null) + { + dtp.setTransferMode(mode); + } + break; + default: + throw new FTPException(response); + } + } + + /** + * Retrieves the specified file. + * @param filename the filename of the file to retrieve + * @return an InputStream containing the file content + */ + public InputStream retrieve(String filename) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + /* + int size = -1; + String cmd = SIZE + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 213: + size = Integer.parseInt(response.getMessage()); + break; + case 550: // File not found + default: + throw new FTPException(response); + } + */ + String cmd = RETR + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getInputStream(); + default: + throw new FTPException(response); + } + } + + /** + * Returns a stream for uploading a file. + * If a file with the same filename already exists on the server, it will + * be overwritten. + * @param filename the name of the file to save the content as + * @return an OutputStream to write the file data to + */ + public OutputStream store(String filename) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + String cmd = STOR + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getOutputStream(); + default: + throw new FTPException(response); + } + } + + /** + * Returns a stream for uploading a file. + * If a file with the same filename already exists on the server, the + * content specified will be appended to the existing file. + * @param filename the name of the file to save the content as + * @return an OutputStream to write the file data to + */ + public OutputStream append(String filename) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + String cmd = APPE + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getOutputStream(); + default: + throw new FTPException(response); + } + } + + /** + * This command may be required by some servers to reserve sufficient + * storage to accommodate the new file to be transferred. + * It should be immediately followed by a <code>store</code> or + * <code>append</code>. + * @param size the number of bytes of storage to allocate + */ + public void allocate(long size) + throws IOException + { + String cmd = ALLO + ' ' + size; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: // OK + case 202: // Superfluous + break; + default: + throw new FTPException(response); + } + } + + /** + * Renames a file. + * @param oldName the current name of the file + * @param newName the new name + * @return true if successful, false otherwise + */ + public boolean rename(String oldName, String newName) + throws IOException + { + String cmd = RNFR + ' ' + oldName; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 450: // File unavailable + case 550: // File not found + return false; + case 350: // Pending + break; + default: + throw new FTPException(response); + } + cmd = RNTO + ' ' + newName; + send(cmd); + response = getResponse(); + switch (response.getCode()) + { + case 250: // OK + return true; + case 450: + case 550: + return false; + default: + throw new FTPException(response); + } + } + + /** + * Aborts the transfer in progress. + * @return true if a transfer was in progress, false otherwise + */ + public boolean abort() + throws IOException + { + send(ABOR); + FTPResponse response = getResponse(); + // Abort client DTP + if (dtp != null) + { + dtp.abort(); + } + switch (response.getCode()) + { + case 226: // successful abort + return false; + case 426: // interrupted + response = getResponse(); + if (response.getCode() == 226) + { + return true; + } + // Otherwise fall through to throw exception + default: + throw new FTPException(response); + } + } + + /** + * Causes the file specified to be deleted at the server site. + * @param filename the file to delete + */ + public boolean delete(String filename) + throws IOException + { + String cmd = DELE + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: // OK + return true; + case 450: // File unavailable + case 550: // File not found + return false; + default: + throw new FTPException(response); + } + } + + /** + * Causes the directory specified to be deleted. + * This may be an absolute or relative pathname. + * @param pathname the directory to delete + */ + public boolean removeDirectory(String pathname) + throws IOException + { + String cmd = RMD + ' ' + pathname; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: // OK + return true; + case 550: // File not found + return false; + default: + throw new FTPException(response); + } + } + + /** + * Causes the directory specified to be created at the server site. + * This may be an absolute or relative pathname. + * @param pathname the directory to create + */ + public boolean makeDirectory(String pathname) + throws IOException + { + String cmd = MKD + ' ' + pathname; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 257: // Directory created + return true; + case 550: // File not found + return false; + default: + throw new FTPException(response); + } + } + + /** + * Returns the current working directory. + */ + public String getWorkingDirectory() + throws IOException + { + send(PWD); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 257: + String message = response.getMessage(); + if (message.charAt(0) == '"') + { + int end = message.indexOf('"', 1); + if (end == -1) + { + throw new ProtocolException(message); + } + return message.substring(1, end); + } + else + { + int end = message.indexOf(' '); + if (end == -1) + { + return message; + } + else + { + return message.substring(0, end); + } + } + default: + throw new FTPException(response); + } + } + + /** + * Returns a listing of information about the specified pathname. + * If the pathname specifies a directory or other group of files, the + * server should transfer a list of files in the specified directory. + * If the pathname specifies a file then the server should send current + * information on the file. A null argument implies the user's + * current working or default directory. + * @param pathname the context pathname, or null + */ + public InputStream list(String pathname) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + if (pathname == null) + { + send(LIST); + } + else + { + String cmd = LIST + ' ' + pathname; + send(cmd); + } + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getInputStream(); + default: + throw new FTPException(response); + } + } + + /** + * Returns a directory listing. The pathname should specify a + * directory or other system-specific file group descriptor; a null + * argument implies the user's current working or default directory. + * @param pathname the directory pathname, or null + * @return a list of filenames(strings) + */ + public List<String> nameList(String pathname) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + if (pathname == null) + { + send(NLST); + } + else + { + String cmd = NLST + ' ' + pathname; + send(cmd); + } + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + InputStream in = dtp.getInputStream(); + in = new BufferedInputStream(in); + in = new CRLFInputStream(in); // TODO ensure that TYPE is correct + LineInputStream li = new LineInputStream(in); + ArrayList<String> ret = new ArrayList<String>(); + for (String line = li.readLine(); + line != null; + line = li.readLine()) + { + ret.add(line); + } + li.close(); + return ret; + default: + throw new FTPException(response); + } + } + + /** + * Returns the type of operating system at the server. + */ + public String system() + throws IOException + { + send(SYST); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 215: + String message = response.getMessage(); + int end = message.indexOf(' '); + if (end == -1) + { + return message; + } + else + { + return message.substring(0, end); + } + default: + throw new FTPException(response); + } + } + + /** + * Does nothing. + * This method can be used to ensure that the connection does not time + * out. + */ + public void noop() + throws IOException + { + send(NOOP); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + break; + default: + throw new FTPException(response); + } + } + + // -- I/O -- + + /** + * Sends the specified command line to the server. + * The CRLF sequence is automatically appended. + * @param cmd the command line to send + */ + protected void send(String cmd) + throws IOException + { + byte[] data = cmd.getBytes(US_ASCII); + out.write(data); + out.writeln(); + out.flush(); + } + + /** + * Reads the next response from the server. + * If the server sends the "transfer complete" code, this is handled here, + * and the next response is passed to the caller. + */ + protected FTPResponse getResponse() + throws IOException + { + FTPResponse response = readResponse(); + if (response.getCode() == 226) + { + if (dtp != null) + { + dtp.transferComplete(); + } + response = readResponse(); + } + return response; + } + + /** + * Reads and parses the next response from the server. + */ + protected FTPResponse readResponse() + throws IOException + { + String line = in.readLine(); + if (line == null) + { + throw new ProtocolException( "EOF"); + } + if (line.length() < 4) + { + throw new ProtocolException(line); + } + int code = parseCode(line); + if (code == -1) + { + throw new ProtocolException(line); + } + char c = line.charAt(3); + if (c == ' ') + { + return new FTPResponse(code, line.substring(4)); + } + else if (c == '-') + { + CPStringBuilder buf = new CPStringBuilder(line.substring(4)); + buf.append('\n'); + while(true) + { + line = in.readLine(); + if (line == null) + { + throw new ProtocolException("EOF"); + } + if (line.length() >= 4 && + line.charAt(3) == ' ' && + parseCode(line) == code) + { + return new FTPResponse(code, line.substring(4), + buf.toString()); + } + else + { + buf.append(line); + buf.append('\n'); + } + } + } + else + { + throw new ProtocolException(line); + } + } + + /* + * Parses the 3-digit numeric code at the beginning of the given line. + * Returns -1 on failure. + */ + static final int parseCode(String line) + { + char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) }; + int ret = 0; + for (int i = 0; i < 3; i++) + { + int digit =((int) c[i]) - 0x30; + if (digit < 0 || digit > 9) + { + return -1; + } + // Computing integer powers is way too expensive in Java! + switch (i) + { + case 0: + ret +=(100 * digit); + break; + case 1: + ret +=(10 * digit); + break; + case 2: + ret += digit; + break; + } + } + return ret; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java new file mode 100644 index 000000000..1a7fcb85d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java @@ -0,0 +1,75 @@ +/* FTPException.java -- + Copyright (C) 2003. 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; + +/** + * An FTP control exception. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class FTPException + extends IOException +{ + + /** + * The response that provoked this exception. + */ + protected final FTPResponse response; + + /** + * Constructs a new FTP exception. + * @param response the response that provoked this exception + */ + public FTPException(FTPResponse response) + { + super(response.getMessage()); + this.response = response; + } + + /** + * Returns the response that provoked this exception. + */ + public FTPResponse getResponse() + { + return response; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java new file mode 100644 index 000000000..2620f0d70 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java @@ -0,0 +1,111 @@ +/* FTPResponse.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +/** + * An FTP control response. + * + * @author Chris Burdess (dog@gnu.org) + */ +public final class FTPResponse +{ + + /** + * The 3-digit status code. + */ + protected final int code; + + /** + * The human-readable message. + */ + protected final String message; + + /** + * Multiline data, if present. + */ + protected final String data; + + /** + * Constructs a new FTP response. + * @param code the status code + * @param message the message + */ + public FTPResponse(int code, String message) + { + this(code, message, null); + } + + /** + * Constructs a new multiline FTP response. + * @param code the status code + * @param message the message + * @param data multiline data + */ + public FTPResponse(int code, String message, String data) + { + this.code = code; + this.message = message; + this.data = data; + } + + /** + * Returns the 3-digit status code. + */ + public int getCode() + { + return code; + } + + /** + * Returns the human-readable message. + */ + public String getMessage() + { + return message; + } + + /** + * Returns the multiline data, or null if there was no such data. + */ + public String getData() + { + return data; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java new file mode 100644 index 000000000..8cc1fafd1 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java @@ -0,0 +1,375 @@ +/* FTPURLConnection.java -- + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import gnu.classpath.SystemProperties; +import gnu.java.net.GetLocalHostAction; + +import java.io.FilterInputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An FTP URL connection. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class FTPURLConnection + extends URLConnection +{ + + /** + * The connection managing the protocol exchange. + */ + protected FTPConnection connection; + + protected boolean passive; + protected int representationType; + protected int fileStructure; + protected int transferMode; + + /** + * Constructs an FTP connection to the specified URL. + * @param url the URL + */ + public FTPURLConnection(URL url) + { + super(url); + passive = true; + representationType = FTPConnection.TYPE_BINARY; + fileStructure = -1; + transferMode = -1; + } + + /** + * Establishes the connection. + */ + public void connect() + throws IOException + { + if (connected) + { + return; + } + String host = url.getHost(); + int port = url.getPort(); + String username = url.getUserInfo(); + String password = null; + if (username != null) + { + int ci = username.indexOf(':'); + if (ci != -1) + { + password = username.substring(ci + 1); + username = username.substring(0, ci); + } + } + else + { + username = "anonymous"; + GetLocalHostAction a = new GetLocalHostAction(); + InetAddress localhost = AccessController.doPrivileged(a); + password = SystemProperties.getProperty("user.name") + "@" + + ((localhost == null) ? "localhost" : localhost.getHostName()); + } + connection = new FTPConnection(host, port); + if (!connection.authenticate(username, password)) + { + throw new SecurityException("Authentication failed"); + } + connection.setPassive(passive); + if (representationType != -1) + { + connection.setRepresentationType(representationType); + } + if (fileStructure != -1) + { + connection.setFileStructure(fileStructure); + } + if (transferMode != -1) + { + connection.setTransferMode(transferMode); + } + } + + /** + * This connection supports doInput. + */ + public void setDoInput(boolean doinput) + { + doInput = doinput; + } + + /** + * This connection supports doOutput. + */ + public void setDoOutput(boolean dooutput) + { + doOutput = dooutput; + } + + /** + * Returns an input stream that reads from this open connection. + */ + public InputStream getInputStream() + throws IOException + { + if (!connected) + { + connect(); + } + String path = url.getPath(); + if (connection.changeWorkingDirectory(path)) + { + return this.new ClosingInputStream(connection.list(null)); + } + else + { + return this.new ClosingInputStream(connection.retrieve(path)); + } + } + + /** + * Returns an output stream that writes to this connection. + */ + public OutputStream getOutputStream() + throws IOException + { + if (!connected) + { + connect(); + } + String path = url.getPath(); + return this.new ClosingOutputStream(connection.store(path)); + } + + public String getRequestProperty(String key) + { + if ("passive".equals(key)) + { + return Boolean.toString(passive); + } + else if ("representationType".equals(key)) + { + switch (representationType) + { + case FTPConnection.TYPE_ASCII: + return "ASCII"; + case FTPConnection.TYPE_EBCDIC: + return "EBCDIC"; + case FTPConnection.TYPE_BINARY: + return "BINARY"; + } + } + else if ("fileStructure".equals(key)) + { + switch (fileStructure) + { + case FTPConnection.STRUCTURE_FILE: + return "FILE"; + case FTPConnection.STRUCTURE_RECORD: + return "RECORD"; + case FTPConnection.STRUCTURE_PAGE: + return "PAGE"; + } + } + else if ("transferMode".equals(key)) + { + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + return "STREAM"; + case FTPConnection.MODE_BLOCK: + return "BLOCK"; + case FTPConnection.MODE_COMPRESSED: + return "COMPRESSED"; + } + } + return null; + } + + public Map<String, List<String>> getRequestProperties() + { + Map<String, List<String>> map = new HashMap<String, List<String>>(); + addRequestPropertyValue(map, "passive"); + addRequestPropertyValue(map, "representationType"); + addRequestPropertyValue(map, "fileStructure"); + addRequestPropertyValue(map, "transferMode"); + return map; + } + + private void addRequestPropertyValue(Map<String, List<String>> map, + String key) + { + String value = getRequestProperty(key); + ArrayList<String> l = new ArrayList<String>(); + l.add(value); + map.put(key, l); + } + + public void setRequestProperty(String key, String value) + { + if (connected) + { + throw new IllegalStateException(); + } + if ("passive".equals(key)) + { + passive = Boolean.valueOf(value).booleanValue(); + } + else if ("representationType".equals(key)) + { + if ("A".equalsIgnoreCase(value) || + "ASCII".equalsIgnoreCase(value)) + { + representationType = FTPConnection.TYPE_ASCII; + } + else if ("E".equalsIgnoreCase(value) || + "EBCDIC".equalsIgnoreCase(value)) + { + representationType = FTPConnection.TYPE_EBCDIC; + } + else if ("I".equalsIgnoreCase(value) || + "BINARY".equalsIgnoreCase(value)) + { + representationType = FTPConnection.TYPE_BINARY; + } + else + { + throw new IllegalArgumentException(value); + } + } + else if ("fileStructure".equals(key)) + { + if ("F".equalsIgnoreCase(value) || + "FILE".equalsIgnoreCase(value)) + { + fileStructure = FTPConnection.STRUCTURE_FILE; + } + else if ("R".equalsIgnoreCase(value) || + "RECORD".equalsIgnoreCase(value)) + { + fileStructure = FTPConnection.STRUCTURE_RECORD; + } + else if ("P".equalsIgnoreCase(value) || + "PAGE".equalsIgnoreCase(value)) + { + fileStructure = FTPConnection.STRUCTURE_PAGE; + } + else + { + throw new IllegalArgumentException(value); + } + } + else if ("transferMode".equals(key)) + { + if ("S".equalsIgnoreCase(value) || + "STREAM".equalsIgnoreCase(value)) + { + transferMode = FTPConnection.MODE_STREAM; + } + else if ("B".equalsIgnoreCase(value) || + "BLOCK".equalsIgnoreCase(value)) + { + transferMode = FTPConnection.MODE_BLOCK; + } + else if ("C".equalsIgnoreCase(value) || + "COMPRESSED".equalsIgnoreCase(value)) + { + transferMode = FTPConnection.MODE_COMPRESSED; + } + else + { + throw new IllegalArgumentException(value); + } + } + } + + public void addRequestProperty(String key, String value) + { + setRequestProperty(key, value); + } + + class ClosingInputStream + extends FilterInputStream + { + + ClosingInputStream(InputStream in) + { + super(in); + } + + public void close() + throws IOException + { + super.close(); + connection.logout(); + } + + } + + class ClosingOutputStream + extends FilterOutputStream + { + + ClosingOutputStream(OutputStream out) + { + super(out); + } + + public void close() + throws IOException + { + super.close(); + connection.logout(); + } + + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java new file mode 100644 index 000000000..7638b6664 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java @@ -0,0 +1,69 @@ +/* Handler.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * An FTP URL stream handler. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Handler + extends URLStreamHandler +{ + + protected int getDefaultPort() + { + return FTPConnection.FTP_PORT; + } + + /** + * Returns an FTPURLConnection for the given URL. + */ + public URLConnection openConnection(URL url) + throws IOException + { + return new FTPURLConnection(url); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java new file mode 100644 index 000000000..a74346c74 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java @@ -0,0 +1,200 @@ +/* PassiveModeDTP.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; + +/** + * A passive mode FTP data transfer process. + * This connects to the host specified and proxies the resulting socket's + * input and output streams. + * + * @author Chris Burdess (dog@gnu.org) + */ +final class PassiveModeDTP + implements DTP +{ + + final String address; + final int port; + Socket socket; + DTPInputStream in; + DTPOutputStream out; + boolean completed; + boolean inProgress; + int transferMode; + + PassiveModeDTP(String address, int port, InetAddress localhost, + int connectionTimeout, int timeout) + throws IOException + { + this.address = address; + this.port = port; + completed = false; + inProgress = false; + socket = new Socket(); + InetSocketAddress remote = new InetSocketAddress(address, port); + InetSocketAddress local = new InetSocketAddress(localhost, port + 1); + socket.bind(local); + if (connectionTimeout > 0) + { + socket.connect(remote, connectionTimeout); + } + else + { + socket.connect(remote); + } + if (timeout > 0) + { + socket.setSoTimeout(timeout); + } + } + + /** + * Returns an input stream from which a remote file can be read. + */ + public InputStream getInputStream() + throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + in = new StreamInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_BLOCK: + in = new BlockInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + in = new CompressedInputStream(this, socket.getInputStream()); + break; + default: + throw new IllegalStateException("Invalid transfer mode"); + } + in.setTransferComplete(false); + return in; + } + + /** + * Returns an output stream to which a local file can be written for + * upload. + */ + public OutputStream getOutputStream() + throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + out = new StreamOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_BLOCK: + out = new BlockOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + out = new CompressedOutputStream(this, socket.getOutputStream()); + break; + default: + throw new IllegalStateException("Invalid transfer mode"); + } + out.setTransferComplete(false); + return out; + } + + public void setTransferMode(int mode) + { + transferMode = mode; + } + + public void complete() + { + completed = true; + if (!inProgress) + { + transferComplete(); + } + } + + public boolean abort() + { + completed = true; + transferComplete(); + return inProgress; + } + + /* + * Called by DTPInputStream or DTPOutputStream when end of + * stream is reached. + */ + public void transferComplete() + { + if (in != null) + { + in.setTransferComplete(true); + } + if (out != null) + { + out.setTransferComplete(true); + } + inProgress = false; + completed = completed ||(transferMode == FTPConnection.MODE_STREAM); + if (completed && socket != null) + { + try + { + socket.close(); + } + catch (IOException e) + { + } + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java new file mode 100644 index 000000000..beee14bcb --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java @@ -0,0 +1,94 @@ +/* StreamInputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A DTP input stream that implements the FTP stream data transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class StreamInputStream + extends DTPInputStream +{ + + StreamInputStream(DTP dtp, InputStream in) + { + super(dtp, in); + } + + public int read() + throws IOException + { + if (transferComplete) + { + return -1; + } + int c = in.read(); + if (c == -1) + { + close(); + } + return c; + } + + public int read(byte[] buf) + throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + if (transferComplete) + { + return -1; + } + int l = in.read(buf, off, len); + if (l == -1) + { + close(); + } + return l; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java new file mode 100644 index 000000000..2df1a87d8 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java @@ -0,0 +1,84 @@ +/* StreamOutputStream.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.ftp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A DTP output stream that implements the FTP stream transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class StreamOutputStream + extends DTPOutputStream +{ + + StreamOutputStream(DTP dtp, OutputStream out) + { + super(dtp, out); + } + + public void write(int c) + throws IOException + { + if (transferComplete) + { + return; + } + out.write(c); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + if (transferComplete) + { + return; + } + out.write(b, off, len); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/package.html b/libjava/classpath/gnu/java/net/protocol/ftp/package.html new file mode 100644 index 000000000..fa3e34d74 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/package.html @@ -0,0 +1,60 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in gnu.java.net.protocol.ftp package. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - gnu.java.net.protocol.ftp</title></head> + +<body> + +<p> +This package contains an FTP client. It can handle both active and passive +mode connections and the various transfer modes and representation types. +</p> + +<p> +Interaction with the server is via a simple stream interface. Only one +concurrent stream (input or output) is supported. +</p> + +<p> +The control connection to the server can be protected using TLS +(the starttls method). +</p> + +</body> +</html> |