001    /*
002     * ftp4j - A pure Java FTP client library
003     * 
004     * Copyright (C) 2008 Carlo Pelliccia (www.sauronsoftware.it)
005     * 
006     * This program is free software: you can redistribute it and/or modify
007     * it under the terms of the GNU General Public License as published by
008     * the Free Software Foundation, either version 3 of the License, or
009     * (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014     * GNU General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018     */
019    package it.sauronsoftware.ftp4j;
020    
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.io.OutputStream;
024    import java.util.ArrayList;
025    import java.util.Iterator;
026    
027    /**
028     * This class is used to represent a communication channel with a FTP server.
029     * 
030     * @author Carlo Pelliccia
031     * @version 1.1
032     */
033    public class FTPCommunicationChannel {
034    
035            /**
036             * The FTPCommunicationListener objects registered on the channel.
037             */
038            private ArrayList communicationListeners = new ArrayList();
039    
040            /**
041             * The connection.
042             */
043            private FTPConnection connection = null;
044    
045            /**
046             * The stream-reader channel established with the remote server.
047             */
048            private NVTASCIIReader reader = null;
049    
050            /**
051             * The stream-writer channel established with the remote server.
052             */
053            private NVTASCIIWriter writer = null;
054    
055            /**
056             * It builds a FTP communication channel.
057             * 
058             * @param connection
059             *            The underlying connection.
060             * @param charsetName
061             *            The name of the charset that has to be used to encode and
062             *            decode the communication.
063             * @throws IOException
064             *             If a I/O error occurs.
065             */
066            public FTPCommunicationChannel(FTPConnection connection, String charsetName)
067                            throws IOException {
068                    this.connection = connection;
069                    InputStream inStream = connection.getInputStream();
070                    OutputStream outStream = connection.getOutputStream();
071                    // Wrap the streams into reader and writer objects.
072                    reader = new NVTASCIIReader(inStream, charsetName);
073                    writer = new NVTASCIIWriter(outStream, charsetName);
074            }
075    
076            /**
077             * This method adds a FTPCommunicationListener to the object.
078             * 
079             * @param listener
080             *            The listener.
081             */
082            public void addCommunicationListener(FTPCommunicationListener listener) {
083                    communicationListeners.add(listener);
084            }
085    
086            /**
087             * This method removes a FTPCommunicationListener previously added to the
088             * object.
089             * 
090             * @param listener
091             *            The listener to be removed.
092             */
093            public void removeCommunicationListener(FTPCommunicationListener listener) {
094                    communicationListeners.remove(listener);
095            }
096    
097            /**
098             * Closes the channel.
099             */
100            public void close() {
101                    try {
102                            connection.close();
103                    } catch (Exception e) {
104                            ;
105                    }
106            }
107    
108            /**
109             * This method returns a list with all the FTPCommunicationListener used by
110             * the client.
111             * 
112             * @return A list with all the FTPCommunicationListener used by the client.
113             */
114            public FTPCommunicationListener[] getCommunicationListeners() {
115                    int size = communicationListeners.size();
116                    FTPCommunicationListener[] ret = new FTPCommunicationListener[size];
117                    for (int i = 0; i < size; i++) {
118                            ret[i] = (FTPCommunicationListener) communicationListeners.get(i);
119                    }
120                    return ret;
121            }
122    
123            /**
124             * This method reads a line from the remote server.
125             * 
126             * @return The string read.
127             * @throws IOException
128             *             If an I/O error occurs during the operation.
129             */
130            private String read() throws IOException {
131                    // Read the line from the server.
132                    String line = reader.readLine();
133                    if (line == null) {
134                            throw new IOException("FTPConnection closed");
135                    }
136                    // Call received() method on every communication listener
137                    // registered.
138                    for (Iterator iter = communicationListeners.iterator(); iter.hasNext();) {
139                            FTPCommunicationListener l = (FTPCommunicationListener) iter.next();
140                            l.received(line);
141                    }
142                    // Return the line read.
143                    return line;
144            }
145    
146            /**
147             * This method sends a command line to the server.
148             * 
149             * @param command
150             *            The command to be sent.
151             * @throws IOException
152             *             If an I/O error occurs.
153             */
154            public void sendFTPCommand(String command) throws IOException {
155                    writer.writeLine(command);
156                    for (Iterator iter = communicationListeners.iterator(); iter.hasNext();) {
157                            FTPCommunicationListener l = (FTPCommunicationListener) iter.next();
158                            l.sent(command);
159                    }
160            }
161    
162            /**
163             * This method reads and parses a FTP reply statement from the server.
164             * 
165             * @return The reply from the server.
166             * @throws IOException
167             *             If an I/O error occurs.
168             * @throws FTPIllegalReplyException
169             *             If the server doesn't reply in a FTP-compliant way.
170             */
171            public FTPReply readFTPReply() throws IOException, FTPIllegalReplyException {
172                    int code = 0;
173                    ArrayList messages = new ArrayList();
174                    do {
175                            String statement = read();
176                            int l = statement.length();
177                            if (code == 0 && l < 3) {
178                                    throw new FTPIllegalReplyException();
179                            }
180                            int aux;
181                            try {
182                                    aux = Integer.parseInt(statement.substring(0, 3));
183                            } catch (Exception e) {
184                                    if (code == 0) {
185                                            throw new FTPIllegalReplyException();
186                                    } else {
187                                            aux = 0;
188                                    }
189                            }
190                            if (code != 0 && aux != 0 && aux != code) {
191                                    throw new FTPIllegalReplyException();
192                            }
193                            if (code == 0) {
194                                    code = aux;
195                            }
196                            if (aux > 0 && l > 3) {
197                                    char s = statement.charAt(3);
198                                    String message = statement.substring(4, l);
199                                    messages.add(message);
200                                    if (s == ' ') {
201                                            break;
202                                    } else if (s == '-') {
203                                            continue;
204                                    } else {
205                                            throw new FTPIllegalReplyException();
206                                    }
207                            } else {
208                                    messages.add(statement);
209                            }
210                    } while (true);
211                    int size = messages.size();
212                    String[] m = new String[size];
213                    for (int i = 0; i < size; i++) {
214                            m[i] = (String) messages.get(i);
215                    }
216                    return new FTPReply(code, m);
217            }
218    
219            /**
220             * Changes the current charset.
221             * 
222             * @param charsetName
223             *            The new charset.
224             * @throws IOException
225             *             If I/O error occurs.
226             * @since 1.1
227             */
228            public void changeCharset(String charsetName) throws IOException {
229                    reader.changeCharset(charsetName);
230                    writer.changeCharset(charsetName);
231            }
232    
233    }