1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.archive.net;
26
27
28 import java.io.BufferedReader;
29 import java.io.IOException;
30 import java.io.Reader;
31 import java.io.StringReader;
32 import java.net.Socket;
33 import java.util.Iterator;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
36
37 import org.apache.commons.io.LineIterator;
38 import org.apache.commons.net.ProtocolCommandEvent;
39 import org.apache.commons.net.ProtocolCommandListener;
40 import org.apache.commons.net.ftp.FTPClient;
41
42 /***
43 * Client for FTP operations. Saves the commands sent to the server and replies
44 * received, which can be retrieved with {@link #getControlConversation()}.
45 *
46 * @author pjack
47 * @author nlevitt
48 */
49 public class ClientFTP extends FTPClient implements ProtocolCommandListener {
50
51 private final Logger logger = Logger.getLogger(this.getClass().getName());
52
53
54 protected StringBuilder controlConversation;
55 protected Socket dataSocket;
56
57 /***
58 * Constructs a new <code>ClientFTP</code>.
59 */
60 public ClientFTP() {
61 controlConversation = new StringBuilder();
62 addProtocolCommandListener(this);
63 }
64
65 /***
66 * Opens a data connection.
67 *
68 * @param command
69 * the data command (eg, RETR or LIST)
70 * @param path
71 * the path of the file to retrieve
72 * @return the socket to read data from, or null if server says not found,
73 * permission denied, etc
74 * @throws IOException
75 * if a network error occurs
76 */
77 public Socket openDataConnection(int command, String path)
78 throws IOException {
79 try {
80 dataSocket = _openDataConnection_(command, path);
81 if (dataSocket != null) {
82 recordAdditionalInfo("Opened data connection to "
83 + dataSocket.getInetAddress().getHostAddress() + ":"
84 + dataSocket.getPort());
85 }
86 return dataSocket;
87 } catch (IOException e) {
88 if (getPassiveHost() != null) {
89 recordAdditionalInfo("Failed to open data connection to "
90 + getPassiveHost() + ":" + getPassivePort() + ": "
91 + e.getMessage());
92 } else {
93 recordAdditionalInfo("Failed to open data connection: "
94 + e.getMessage());
95 }
96 throw e;
97 }
98 }
99
100 public void closeDataConnection() {
101 if (dataSocket != null) {
102 String dataHostPort = dataSocket.getInetAddress().getHostAddress()
103 + ":" + dataSocket.getPort();
104 try {
105 dataSocket.close();
106 recordAdditionalInfo("Closed data connection to "
107 + dataHostPort);
108 } catch (IOException e) {
109 recordAdditionalInfo("Problem closing data connection to "
110 + dataHostPort + ": " + e.getMessage());
111 }
112 }
113 }
114
115 protected void _connectAction_() throws IOException {
116 try {
117 recordAdditionalInfo("Opening control connection to "
118 + getRemoteAddress().getHostAddress() + ":"
119 + getRemotePort());
120 super._connectAction_();
121 } catch (IOException e) {
122 recordAdditionalInfo("Failed to open control connection to "
123 + getRemoteAddress().getHostAddress() + ":"
124 + getRemotePort() + ": " + e.getMessage());
125 throw e;
126 }
127 }
128
129 public void disconnect() throws IOException {
130 String remoteHostPort = getRemoteAddress().getHostAddress() + ":"
131 + getRemotePort();
132 super.disconnect();
133 recordAdditionalInfo("Closed control connection to " + remoteHostPort);
134 }
135
136 public String getControlConversation() {
137 return controlConversation.toString();
138 }
139
140 private class IterableLineIterator extends LineIterator implements Iterable<String> {
141 public IterableLineIterator(final Reader reader) throws IllegalArgumentException {
142 super(reader);
143 }
144 @SuppressWarnings("unchecked")
145 public Iterator<String> iterator() {
146 return this;
147 }
148 }
149
150 protected void recordControlMessage(String linePrefix, String message) {
151 for (String line: new IterableLineIterator(new BufferedReader(new StringReader(message)))) {
152 controlConversation.append(linePrefix);
153 controlConversation.append(line);
154 controlConversation.append(NETASCII_EOL);
155 if (logger.isLoggable(Level.FINEST)) {
156 logger.finest(linePrefix + line);
157 }
158 }
159 }
160
161 public void protocolCommandSent(ProtocolCommandEvent event) {
162 recordControlMessage("> ", event.getMessage());
163 }
164
165 public void protocolReplyReceived(ProtocolCommandEvent event) {
166 recordControlMessage("< ", event.getMessage());
167 }
168
169
170 private void recordAdditionalInfo(String message) {
171 recordControlMessage("* ", message);
172 }
173
174
175 @Override
176 public String[] getReplyStrings() {
177 return _replyLines.toArray(new String[0]);
178 }
179 }