63 |
*/ |
*/ |
64 |
public static final int FTP_PORT = 21; |
public static final int FTP_PORT = 21; |
65 |
|
|
66 |
/** |
/** |
67 |
* The FTP data port. |
* The FTP data port. |
68 |
*/ |
*/ |
69 |
public static final int FTP_DATA_PORT = 20; |
public static final int FTP_DATA_PORT = 20; |
70 |
|
|
71 |
// -- FTP vocabulary -- |
// -- FTP vocabulary -- |
72 |
protected static final String USER = "USER"; |
protected static final String USER = "USER"; |
73 |
protected static final String PASS = "PASS"; |
protected static final String PASS = "PASS"; |
74 |
protected static final String ACCT = "ACCT"; |
protected static final String ACCT = "ACCT"; |
75 |
protected static final String CWD = "CWD"; |
protected static final String CWD = "CWD"; |
76 |
protected static final String CDUP = "CDUP"; |
protected static final String CDUP = "CDUP"; |
77 |
protected static final String SMNT = "SMNT"; |
protected static final String SMNT = "SMNT"; |
78 |
protected static final String REIN = "REIN"; |
protected static final String REIN = "REIN"; |
79 |
protected static final String QUIT = "QUIT"; |
protected static final String QUIT = "QUIT"; |
80 |
|
|
81 |
protected static final String PORT = "PORT"; |
protected static final String PORT = "PORT"; |
82 |
protected static final String PASV = "PASV"; |
protected static final String PASV = "PASV"; |
83 |
protected static final String TYPE = "TYPE"; |
protected static final String TYPE = "TYPE"; |
84 |
protected static final String STRU = "STRU"; |
protected static final String STRU = "STRU"; |
85 |
protected static final String MODE = "MODE"; |
protected static final String MODE = "MODE"; |
86 |
|
|
87 |
protected static final String RETR = "RETR"; |
protected static final String RETR = "RETR"; |
88 |
protected static final String STOR = "STOR"; |
protected static final String STOR = "STOR"; |
89 |
protected static final String STOU = "STOU"; |
protected static final String STOU = "STOU"; |
90 |
protected static final String APPE = "APPE"; |
protected static final String APPE = "APPE"; |
91 |
protected static final String ALLO = "ALLO"; |
protected static final String ALLO = "ALLO"; |
92 |
protected static final String REST = "REST"; |
protected static final String REST = "REST"; |
93 |
protected static final String RNFR = "RNFR"; |
protected static final String RNFR = "RNFR"; |
94 |
protected static final String RNTO = "RNTO"; |
protected static final String RNTO = "RNTO"; |
95 |
protected static final String ABOR = "ABOR"; |
protected static final String ABOR = "ABOR"; |
96 |
protected static final String DELE = "DELE"; |
protected static final String DELE = "DELE"; |
97 |
protected static final String RMD = "RMD"; |
protected static final String RMD = "RMD"; |
98 |
protected static final String MKD = "MKD"; |
protected static final String MKD = "MKD"; |
99 |
protected static final String PWD = "PWD"; |
protected static final String PWD = "PWD"; |
100 |
protected static final String LIST = "LIST"; |
protected static final String LIST = "LIST"; |
101 |
protected static final String NLST = "NLST"; |
protected static final String NLST = "NLST"; |
102 |
protected static final String SITE = "SITE"; |
protected static final String SITE = "SITE"; |
103 |
protected static final String SYST = "SYST"; |
protected static final String SYST = "SYST"; |
104 |
protected static final String STAT = "STAT"; |
protected static final String STAT = "STAT"; |
105 |
protected static final String HELP = "HELP"; |
protected static final String HELP = "HELP"; |
106 |
protected static final String NOOP = "NOOP"; |
protected static final String NOOP = "NOOP"; |
107 |
|
|
108 |
public static final int TYPE_ASCII = 1; |
public static final int TYPE_ASCII = 1; |
109 |
public static final int TYPE_EBCDIC = 2; |
public static final int TYPE_EBCDIC = 2; |
110 |
public static final int TYPE_BINARY = 3; |
public static final int TYPE_BINARY = 3; |
111 |
|
|
112 |
public static final int STRUCTURE_FILE = 1; |
public static final int STRUCTURE_FILE = 1; |
113 |
public static final int STRUCTURE_RECORD = 2; |
public static final int STRUCTURE_RECORD = 2; |
114 |
public static final int STRUCTURE_PAGE = 3; |
public static final int STRUCTURE_PAGE = 3; |
115 |
|
|
116 |
public static final int MODE_STREAM = 1; |
public static final int MODE_STREAM = 1; |
117 |
public static final int MODE_BLOCK = 2; |
public static final int MODE_BLOCK = 2; |
118 |
public static final int MODE_COMPRESSED = 3; |
public static final int MODE_COMPRESSED = 3; |
119 |
|
|
120 |
// -- Telnet constants -- |
// -- Telnet constants -- |
121 |
private static final String US_ASCII = "US-ASCII"; |
private static final String US_ASCII = "US-ASCII"; |
122 |
private static final byte[] CRLF = { 0x0d, 0x0a }; |
private static final byte[] CRLF = { 0x0d, 0x0a }; |
123 |
|
|
124 |
/** |
/** |
125 |
* The socket used to communicate with the server. |
* The socket used to communicate with the server. |
126 |
*/ |
*/ |
127 |
protected Socket socket; |
protected Socket socket; |
128 |
|
|
129 |
/** |
/** |
130 |
* The socket input stream. |
* The socket input stream. |
131 |
*/ |
*/ |
132 |
protected LineInputStream in; |
protected LineInputStream in; |
133 |
|
|
134 |
/** |
/** |
135 |
* The socket output stream. |
* The socket output stream. |
136 |
*/ |
*/ |
137 |
protected OutputStream out; |
protected OutputStream out; |
138 |
|
|
139 |
/** |
/** |
140 |
* If true, print debugging information. |
* If true, print debugging information. |
141 |
*/ |
*/ |
142 |
protected boolean debug; |
protected boolean debug; |
143 |
|
|
144 |
/** |
/** |
145 |
* The current data transfer process in use by this connection. |
* The current data transfer process in use by this connection. |
146 |
*/ |
*/ |
147 |
protected DTP dtp; |
protected DTP dtp; |
148 |
|
|
149 |
/** |
/** |
150 |
* The current representation type. |
* The current representation type. |
151 |
*/ |
*/ |
152 |
protected int representationType = TYPE_ASCII; |
protected int representationType = TYPE_ASCII; |
153 |
|
|
154 |
/** |
/** |
155 |
* The current file structure type. |
* The current file structure type. |
156 |
*/ |
*/ |
157 |
protected int fileStructure = STRUCTURE_FILE; |
protected int fileStructure = STRUCTURE_FILE; |
158 |
|
|
159 |
/** |
/** |
160 |
* The current transfer mode. |
* The current transfer mode. |
161 |
*/ |
*/ |
162 |
protected int transferMode = MODE_STREAM; |
protected int transferMode = MODE_STREAM; |
163 |
|
|
164 |
/** |
/** |
165 |
* If true, use passive mode. |
* If true, use passive mode. |
166 |
*/ |
*/ |
167 |
protected boolean passive = false; |
protected boolean passive = false; |
168 |
|
|
169 |
/** |
/** |
170 |
* Creates a new connection to the server using the default port. |
* Creates a new connection to the server using the default port. |
171 |
* @param hostname the hostname of the server to connect to |
* @param hostname the hostname of the server to connect to |
172 |
*/ |
*/ |
173 |
public FTPConnection(String hostname) |
public FTPConnection(String hostname) |
174 |
throws UnknownHostException, IOException |
throws UnknownHostException, IOException |
175 |
{ |
{ |
176 |
this(hostname, -1, -1, -1, false); |
this(hostname, -1, -1, -1, false); |
177 |
} |
} |
178 |
|
|
179 |
/** |
/** |
180 |
* Creates a new connection to the server. |
* Creates a new connection to the server. |
181 |
* @param hostname the hostname of the server to connect to |
* @param hostname the hostname of the server to connect to |
182 |
* @param port the port to connect to (if <=0, use default port) |
* @param port the port to connect to (if <=0, use default port) |
183 |
*/ |
*/ |
184 |
public FTPConnection(String hostname, int port) |
public FTPConnection(String hostname, int port) |
185 |
throws UnknownHostException, IOException |
throws UnknownHostException, IOException |
186 |
{ |
{ |
187 |
this(hostname, port, -1, -1, false); |
this(hostname, port, -1, -1, false); |
188 |
} |
} |
189 |
|
|
190 |
/** |
/** |
191 |
* Creates a new connection to the server. |
* Creates a new connection to the server. |
192 |
* @param hostname the hostname of the server to connect to |
* @param hostname the hostname of the server to connect to |
196 |
* @param debug print debugging information |
* @param debug print debugging information |
197 |
*/ |
*/ |
198 |
public FTPConnection(String hostname, int port, |
public FTPConnection(String hostname, int port, |
199 |
int connectionTimeout, int timeout, boolean debug) |
int connectionTimeout, int timeout, boolean debug) |
200 |
throws UnknownHostException, IOException |
throws UnknownHostException, IOException |
201 |
{ |
{ |
202 |
this.debug = debug; |
this.debug = debug; |
203 |
if (port<=0) |
if (port <= 0) |
204 |
port = FTP_PORT; |
port = FTP_PORT; |
205 |
|
|
206 |
// Set up socket |
// Set up socket |
207 |
// TODO connection timeout |
// TODO connection timeout |
208 |
socket = new Socket(hostname, port); |
socket = new Socket(hostname, port); |
209 |
if (timeout>0) |
if (timeout > 0) |
210 |
socket.setSoTimeout(timeout); |
socket.setSoTimeout(timeout); |
211 |
|
|
212 |
InputStream in = socket.getInputStream(); |
InputStream in = socket.getInputStream(); |
213 |
in = new BufferedInputStream(in); |
in = new BufferedInputStream(in); |
214 |
in = new CRLFInputStream(in); |
in = new CRLFInputStream(in); |
215 |
this.in = new LineInputStream(in); |
this.in = new LineInputStream(in); |
216 |
OutputStream out = socket.getOutputStream(); |
OutputStream out = socket.getOutputStream(); |
217 |
this.out = new BufferedOutputStream(out); |
this.out = new BufferedOutputStream(out); |
218 |
|
|
219 |
// Read greeting |
// Read greeting |
220 |
FTPResponse response = getResponse(); |
FTPResponse response = getResponse(); |
221 |
switch (response.getCode()) |
switch (response.getCode()) |
222 |
{ |
{ |
223 |
case 220: // hello |
case 220: // hello |
224 |
break; |
break; |
225 |
default: |
default:throw new FTPException(response); |
226 |
throw new FTPException(response); |
} |
227 |
} |
} |
|
} |
|
228 |
|
|
229 |
/** |
/** |
230 |
* Authenticate using the specified username and password. |
* Authenticate using the specified username and password. |
231 |
* If the username suffices for the server, the password will not be used |
* If the username suffices for the server, the password will not be used |
232 |
* and may be null. |
* and may be null. |
234 |
* @param password the optional password |
* @param password the optional password |
235 |
* @return true on success, false otherwise |
* @return true on success, false otherwise |
236 |
*/ |
*/ |
237 |
public boolean authenticate(String username, String password) |
public boolean authenticate(String username, String password) |
238 |
throws IOException |
throws IOException |
239 |
{ |
{ |
240 |
String cmd = new StringBuffer(USER) |
String cmd = |
241 |
.append(' ') |
new StringBuffer(USER).append(' ').append(username).toString(); |
242 |
.append(username) |
send(cmd); |
243 |
.toString(); |
FTPResponse response = getResponse(); |
244 |
send(cmd); |
switch (response.getCode()) |
245 |
FTPResponse response = getResponse(); |
{ |
246 |
switch (response.getCode()) |
case 230: // User logged in |
247 |
{ |
return true; |
248 |
case 230: // User logged in |
case 331: // User name okay, need password |
249 |
return true; |
break; |
250 |
case 331: // User name okay, need password |
case 332: // Need account for login |
251 |
break; |
case 530: // No such user |
252 |
case 332: // Need account for login |
return false; |
253 |
case 530: // No such user |
default:throw new FTPException(response); |
254 |
return false; |
} |
255 |
default: |
cmd = new StringBuffer(PASS).append(' ').append(password).toString(); |
256 |
throw new FTPException(response); |
send(cmd); |
257 |
} |
response = getResponse(); |
258 |
cmd = new StringBuffer(PASS) |
switch (response.getCode()) |
259 |
.append(' ') |
{ |
260 |
.append(password) |
case 230: // User logged in |
261 |
.toString(); |
case 202: // Superfluous |
262 |
send(cmd); |
return true; |
263 |
response = getResponse(); |
case 332: // Need account for login |
264 |
switch (response.getCode()) |
case 530: // Bad password |
265 |
{ |
return false; |
266 |
case 230: // User logged in |
default: |
267 |
case 202: // Superfluous |
throw new FTPException(response); |
268 |
return true; |
} |
269 |
case 332: // Need account for login |
} |
|
case 530: // Bad password |
|
|
return false; |
|
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
270 |
|
|
271 |
/** |
/** |
272 |
* Changes directory to the specified path. |
* Changes directory to the specified path. |
273 |
* @param path an absolute or relative pathname |
* @param path an absolute or relative pathname |
274 |
* @return true on success, false if the specified path does not exist |
* @return true on success, false if the specified path does not exist |
275 |
*/ |
*/ |
276 |
public boolean changeWorkingDirectory(String path) |
public boolean changeWorkingDirectory(String path) throws IOException |
277 |
throws IOException |
{ |
278 |
{ |
String cmd = new StringBuffer(CWD).append(' ').append(path).toString(); |
279 |
String cmd = new StringBuffer(CWD) |
send(cmd); |
280 |
.append(' ') |
FTPResponse response = getResponse(); |
281 |
.append(path) |
switch (response.getCode()) |
282 |
.toString(); |
{ |
283 |
send(cmd); |
case 250: |
284 |
FTPResponse response = getResponse(); |
return true; |
285 |
switch (response.getCode()) |
case 550:return false; |
286 |
{ |
default:throw new FTPException(response); |
287 |
case 250: |
} |
288 |
return true; |
} |
|
case 550: |
|
|
return false; |
|
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
289 |
|
|
290 |
/** |
/** |
291 |
* Changes directory to the parent of the current working directory. |
* Changes directory to the parent of the current working directory. |
292 |
* @return true on success, false otherwise |
* @return true on success, false otherwise |
293 |
*/ |
*/ |
294 |
public boolean changeToParentDirectory() |
public boolean changeToParentDirectory() throws IOException |
295 |
throws IOException |
{ |
296 |
{ |
send(CDUP); |
297 |
send(CDUP); |
FTPResponse response = getResponse(); |
298 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
299 |
switch (response.getCode()) |
{ |
300 |
{ |
case 250: |
301 |
case 250: |
return true; |
302 |
return true; |
case 550:return false; |
303 |
case 550: |
default:throw new FTPException(response); |
304 |
return false; |
} |
305 |
default: |
} |
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
306 |
|
|
307 |
/** |
/** |
308 |
* Terminates an authenticated login. |
* Terminates an authenticated login. |
309 |
* If file transfer is in progress, it remains active for result response |
* If file transfer is in progress, it remains active for result response |
310 |
* only. |
* only. |
311 |
*/ |
*/ |
312 |
public void reinitialize() |
public void reinitialize() throws IOException |
313 |
throws IOException |
{ |
314 |
{ |
send(REIN); |
315 |
send(REIN); |
FTPResponse response = getResponse(); |
316 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
317 |
switch (response.getCode()) |
{ |
318 |
{ |
case 220: |
319 |
case 220: |
if (dtp != null) |
320 |
if (dtp!=null) |
{ |
321 |
{ |
dtp.complete(); |
322 |
dtp.complete(); |
dtp = null; |
323 |
dtp = null; |
} |
324 |
} |
break; |
325 |
break; |
default: |
326 |
default: |
throw new FTPException(response); |
327 |
throw new FTPException(response); |
} |
328 |
} |
} |
|
} |
|
329 |
|
|
330 |
/** |
/** |
331 |
* Terminates the control connection. |
* Terminates the control connection. |
332 |
* The file transfer connection remains open for result response only. |
* The file transfer connection remains open for result response only. |
333 |
* This connection is invalid and no further commands may be issued. |
* This connection is invalid and no further commands may be issued. |
334 |
*/ |
*/ |
335 |
public void logout() |
public void logout() throws IOException |
336 |
throws IOException |
{ |
337 |
{ |
send(QUIT); |
338 |
send(QUIT); |
try |
339 |
try |
{ |
340 |
{ |
getResponse(); // not required |
341 |
getResponse(); // not required |
} |
342 |
} |
catch(IOException e) |
343 |
catch (IOException e) |
{ |
344 |
{ |
} |
345 |
} |
if (dtp != null) |
346 |
if (dtp!=null) |
{ |
347 |
{ |
dtp.complete(); |
348 |
dtp.complete(); |
dtp = null; |
349 |
dtp = null; |
} |
350 |
} |
try |
351 |
try |
{ |
352 |
{ |
socket.close(); |
353 |
socket.close(); |
} |
354 |
} |
catch(IOException e) |
355 |
catch (IOException e) |
{ |
356 |
{ |
} |
357 |
} |
} |
|
} |
|
358 |
|
|
359 |
/** |
/** |
360 |
* Initialise the data transfer process. |
* Initialise the data transfer process. |
361 |
*/ |
*/ |
362 |
protected void initialiseDTP() |
protected void initialiseDTP() throws IOException |
363 |
throws IOException |
{ |
364 |
{ |
if (dtp != null) |
365 |
if (dtp!=null) |
{ |
366 |
{ |
dtp.complete(); |
367 |
dtp.complete(); |
dtp = null; |
368 |
dtp = null; |
} |
369 |
} |
|
370 |
|
InetAddress localhost = socket.getLocalAddress(); |
371 |
InetAddress localhost = socket.getLocalAddress(); |
if (passive) |
372 |
if (passive) |
{ |
373 |
{ |
send(PASV); |
374 |
send(PASV); |
FTPResponse response = getResponse(); |
375 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
376 |
switch (response.getCode()) |
{ |
377 |
{ |
case 227: |
378 |
case 227: |
String message = response.getMessage(); |
379 |
String message = response.getMessage(); |
try |
380 |
try |
{ |
381 |
{ |
int start = message.indexOf(','); |
382 |
int start = message.indexOf(','); |
char c = message.charAt(start - 1); |
383 |
char c = message.charAt(start-1); |
while (c > 0x30 && c < 0x39) |
384 |
while (c>0x30 && c<0x39) |
c = message.charAt((--start) - 1); |
385 |
c = message.charAt((--start)-1); |
int mid1 = start; |
386 |
int mid1 = start; |
for (int i = 0; i < 4; i++) |
387 |
for (int i=0; i<4; i++) |
mid1 = message.indexOf(',', mid1 + 1); |
388 |
mid1 = message.indexOf(',', mid1+1); |
int mid2 = message.indexOf(',', mid1 + 1); |
389 |
int mid2 = message.indexOf(',', mid1+1); |
int end = mid2; |
390 |
int end = mid2; |
c = message.charAt(end + 1); |
391 |
c = message.charAt(end+1); |
while (c > 0x30 && c < 0x39) |
392 |
while (c>0x30 && c<0x39) |
c = message.charAt((++end) + 1); |
393 |
c = message.charAt((++end)+1); |
|
394 |
|
String address = message.substring(start, mid1).replace(',', '.'); |
395 |
String address = message.substring(start, mid1).replace(',', '.'); |
int port_hi = Integer.parseInt(message.substring(mid1 + 1, mid2)); |
396 |
int port_hi = Integer.parseInt(message.substring(mid1+1, mid2)); |
int port_lo = |
397 |
int port_lo = Integer.parseInt(message.substring(mid2+1, end+1)); |
Integer.parseInt(message.substring(mid2 + 1, end + 1)); |
398 |
int port = (port_hi<<8) | port_lo; |
int port = (port_hi << 8) | port_lo; |
399 |
|
|
400 |
System.out.println("Entering passive mode: "+address+":"+port); |
System.out.println("Entering passive mode: " + address + ":" + |
401 |
dtp = new PassiveModeDTP(address, port, localhost); |
port); |
402 |
break; |
dtp = new PassiveModeDTP(address, port, localhost); |
403 |
} |
break; |
404 |
catch (ArrayIndexOutOfBoundsException e) |
} |
405 |
{ |
catch(ArrayIndexOutOfBoundsException e) |
406 |
throw new ProtocolException(e.getMessage()+": "+message); |
{ |
407 |
} |
throw new ProtocolException(e.getMessage() + ": " + message); |
408 |
catch (NumberFormatException e) |
} |
409 |
{ |
catch(NumberFormatException e) |
410 |
throw new ProtocolException(e.getMessage()+": "+message); |
{ |
411 |
} |
throw new ProtocolException(e.getMessage() + ": " + message); |
412 |
default: |
} |
413 |
throw new FTPException(response); |
default: |
414 |
} |
throw new FTPException(response); |
415 |
} |
} |
416 |
else |
} |
417 |
{ |
else |
418 |
// Get the local port |
{ |
419 |
int port = socket.getLocalPort()+1; |
// Get the local port |
420 |
int tries = 0; |
int port = socket.getLocalPort() + 1; |
421 |
// Bind the active mode DTP |
int tries = 0; |
422 |
while (dtp==null) |
// Bind the active mode DTP |
423 |
{ |
while (dtp == null) |
424 |
try |
{ |
425 |
{ |
try |
426 |
dtp = new ActiveModeDTP(localhost, port); |
{ |
427 |
System.out.println("Listening on: "+port); |
dtp = new ActiveModeDTP(localhost, port); |
428 |
} |
System.out.println("Listening on: " + port); |
429 |
catch (BindException e) |
} |
430 |
{ |
catch(BindException e) |
431 |
port++; |
{ |
432 |
tries++; |
port++; |
433 |
if (tries>9) |
tries++; |
434 |
throw e; |
if (tries > 9) |
435 |
} |
throw e; |
436 |
} |
} |
437 |
|
} |
438 |
// Send PORT command |
|
439 |
StringBuffer buf = new StringBuffer(PORT); |
// Send PORT command |
440 |
buf.append(' '); |
StringBuffer buf = new StringBuffer(PORT); |
441 |
// Construct the address/port string form |
buf.append(' '); |
442 |
byte[] address = localhost.getAddress(); |
// Construct the address/port string form |
443 |
for (int i=0; i<address.length; i++) |
byte[]address = localhost.getAddress(); |
444 |
{ |
for (int i = 0; i < address.length; i++) |
445 |
int a = (int)address[i]; |
{ |
446 |
if (a<0) |
int a = (int) address[i]; |
447 |
a += 0x100; |
if (a < 0) |
448 |
buf.append(a); |
a += 0x100; |
449 |
buf.append(','); |
buf.append(a); |
450 |
} |
buf.append(','); |
451 |
int port_hi = (port & 0xff00) >> 8; |
} |
452 |
int port_lo = (port & 0x00ff); |
int port_hi = (port & 0xff00) >> 8; |
453 |
buf.append(port_hi); |
int port_lo = (port & 0x00ff); |
454 |
buf.append(','); |
buf.append(port_hi); |
455 |
buf.append(port_lo); |
buf.append(','); |
456 |
send(buf.toString()); |
buf.append(port_lo); |
457 |
// Get response |
send(buf.toString()); |
458 |
FTPResponse response = getResponse(); |
// Get response |
459 |
switch (response.getCode()) |
FTPResponse response = getResponse(); |
460 |
{ |
switch (response.getCode()) |
461 |
case 200: // OK |
{ |
462 |
break; |
case 200: // OK |
463 |
default: |
break; |
464 |
dtp.abort(); |
default: |
465 |
dtp = null; |
dtp.abort(); |
466 |
throw new FTPException(response); |
dtp = null; |
467 |
} |
throw new FTPException(response); |
468 |
} |
} |
469 |
dtp.setTransferMode(transferMode); |
} |
470 |
} |
dtp.setTransferMode(transferMode); |
471 |
|
} |
472 |
/** |
|
473 |
|
/** |
474 |
* Set passive mode. |
* Set passive mode. |
475 |
* @param flag true if we should use passive mode, false otherwise |
* @param flag true if we should use passive mode, false otherwise |
476 |
*/ |
*/ |
477 |
public void setPassive(boolean flag) |
public void setPassive(boolean flag) throws IOException |
478 |
throws IOException |
{ |
479 |
{ |
if (passive != flag) |
480 |
if (passive!=flag) |
{ |
481 |
{ |
passive = flag; |
482 |
passive = flag; |
initialiseDTP(); |
483 |
initialiseDTP(); |
} |
484 |
} |
} |
|
} |
|
485 |
|
|
486 |
/** |
/** |
487 |
* Returns the current representation type of the transfer data. |
* Returns the current representation type of the transfer data. |
488 |
* @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY |
* @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY |
489 |
*/ |
*/ |
490 |
public int getRepresentationType() |
public int getRepresentationType() |
491 |
{ |
{ |
492 |
return representationType; |
return representationType; |
493 |
} |
} |
494 |
|
|
495 |
/** |
/** |
496 |
* Sets the desired representation type of the transfer data. |
* Sets the desired representation type of the transfer data. |
497 |
* @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY |
* @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY |
498 |
*/ |
*/ |
499 |
public void setRepresentationType(int type) |
public void setRepresentationType(int type) throws IOException |
500 |
throws IOException |
{ |
501 |
{ |
StringBuffer buf = new StringBuffer(TYPE); |
502 |
StringBuffer buf = new StringBuffer(TYPE); |
buf.append(' '); |
503 |
buf.append(' '); |
switch (type) |
504 |
switch (type) |
{ |
505 |
{ |
case TYPE_ASCII: |
506 |
case TYPE_ASCII: |
buf.append('A'); |
507 |
buf.append('A'); |
break; |
508 |
break; |
case TYPE_EBCDIC:buf.append('E'); |
509 |
case TYPE_EBCDIC: |
break; |
510 |
buf.append('E'); |
case TYPE_BINARY:buf.append('I'); |
511 |
break; |
break; |
512 |
case TYPE_BINARY: |
default:throw new IllegalArgumentException(Integer.toString(type)); |
513 |
buf.append('I'); |
} |
514 |
break; |
//buf.append(' '); |
515 |
default: |
//buf.append('N'); |
516 |
throw new IllegalArgumentException(Integer.toString(type)); |
send(buf.toString()); |
517 |
} |
FTPResponse response = getResponse(); |
518 |
//buf.append(' '); |
switch (response.getCode()) |
519 |
//buf.append('N'); |
{ |
520 |
send(buf.toString()); |
case 200: |
521 |
FTPResponse response = getResponse(); |
representationType = type; |
522 |
switch (response.getCode()) |
break; |
523 |
{ |
default: |
524 |
case 200: |
throw new FTPException(response); |
525 |
representationType = type; |
} |
526 |
break; |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
527 |
|
|
528 |
/** |
/** |
529 |
* Returns the current file structure type. |
* Returns the current file structure type. |
530 |
* @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE |
* @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE |
531 |
*/ |
*/ |
532 |
public int getFileStructure() |
public int getFileStructure() |
533 |
{ |
{ |
534 |
return fileStructure; |
return fileStructure; |
535 |
} |
} |
536 |
|
|
537 |
/** |
/** |
538 |
* Sets the desired file structure type. |
* Sets the desired file structure type. |
539 |
* @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE |
* @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE |
540 |
*/ |
*/ |
541 |
public void setFileStructure(int structure) |
public void setFileStructure(int structure) throws IOException |
542 |
throws IOException |
{ |
543 |
{ |
StringBuffer buf = new StringBuffer(STRU); |
544 |
StringBuffer buf = new StringBuffer(STRU); |
buf.append(' '); |
545 |
buf.append(' '); |
switch (structure) |
546 |
switch (structure) |
{ |
547 |
{ |
case STRUCTURE_FILE: |
548 |
case STRUCTURE_FILE: |
buf.append('F'); |
549 |
buf.append('F'); |
break; |
550 |
break; |
case STRUCTURE_RECORD:buf.append('R'); |
551 |
case STRUCTURE_RECORD: |
break; |
552 |
buf.append('R'); |
case STRUCTURE_PAGE:buf.append('P'); |
553 |
break; |
break; |
554 |
case STRUCTURE_PAGE: |
default:throw new IllegalArgumentException(Integer.toString(structure)); |
555 |
buf.append('P'); |
} |
556 |
break; |
send(buf.toString()); |
557 |
default: |
FTPResponse response = getResponse(); |
558 |
throw new IllegalArgumentException(Integer.toString(structure)); |
switch (response.getCode()) |
559 |
} |
{ |
560 |
send(buf.toString()); |
case 200: |
561 |
FTPResponse response = getResponse(); |
fileStructure = structure; |
562 |
switch (response.getCode()) |
break; |
563 |
{ |
default: |
564 |
case 200: |
throw new FTPException(response); |
565 |
fileStructure = structure; |
} |
566 |
break; |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
567 |
|
|
568 |
/** |
/** |
569 |
* Returns the current transfer mode. |
* Returns the current transfer mode. |
570 |
* @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED |
* @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED |
571 |
*/ |
*/ |
572 |
public int getTransferMode() |
public int getTransferMode() |
573 |
{ |
{ |
574 |
return transferMode; |
return transferMode; |
575 |
} |
} |
576 |
|
|
577 |
/** |
/** |
578 |
* Sets the desired transfer mode. |
* Sets the desired transfer mode. |
579 |
* @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED |
* @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED |
580 |
*/ |
*/ |
581 |
public void setTransferMode(int mode) |
public void setTransferMode(int mode) throws IOException |
582 |
throws IOException |
{ |
583 |
{ |
StringBuffer buf = new StringBuffer(MODE); |
584 |
StringBuffer buf = new StringBuffer(MODE); |
buf.append(' '); |
585 |
buf.append(' '); |
switch (mode) |
586 |
switch (mode) |
{ |
587 |
{ |
case MODE_STREAM: |
588 |
case MODE_STREAM: |
buf.append('S'); |
589 |
buf.append('S'); |
break; |
590 |
break; |
case MODE_BLOCK:buf.append('B'); |
591 |
case MODE_BLOCK: |
break; |
592 |
buf.append('B'); |
case MODE_COMPRESSED:buf.append('C'); |
593 |
break; |
break; |
594 |
case MODE_COMPRESSED: |
default:throw new IllegalArgumentException(Integer.toString(mode)); |
595 |
buf.append('C'); |
} |
596 |
break; |
send(buf.toString()); |
597 |
default: |
FTPResponse response = getResponse(); |
598 |
throw new IllegalArgumentException(Integer.toString(mode)); |
switch (response.getCode()) |
599 |
} |
{ |
600 |
send(buf.toString()); |
case 200: |
601 |
FTPResponse response = getResponse(); |
transferMode = mode; |
602 |
switch (response.getCode()) |
if (dtp != null) |
603 |
{ |
dtp.setTransferMode(mode); |
604 |
case 200: |
break; |
605 |
transferMode = mode; |
default: |
606 |
if (dtp!=null) |
throw new FTPException(response); |
607 |
dtp.setTransferMode(mode); |
} |
608 |
break; |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
609 |
|
|
610 |
/** |
/** |
611 |
* Retrieves the specified file. |
* Retrieves the specified file. |
612 |
* @param filename the filename of the file to retrieve |
* @param filename the filename of the file to retrieve |
613 |
* @return an InputStream containing the file content |
* @return an InputStream containing the file content |
614 |
*/ |
*/ |
615 |
public InputStream retrieve(String filename) |
public InputStream retrieve(String filename) throws IOException |
616 |
throws IOException |
{ |
617 |
{ |
if (dtp == null || transferMode == MODE_STREAM) |
618 |
if (dtp==null || transferMode==MODE_STREAM) |
initialiseDTP(); |
619 |
initialiseDTP(); |
/* |
620 |
/* |
int size = -1; |
621 |
int size = -1; |
String cmd = new StringBuffer(SIZE) |
622 |
String cmd = new StringBuffer(SIZE) |
.append(' ') |
623 |
.append(' ') |
.append(filename) |
624 |
.append(filename) |
.toString(); |
625 |
.toString(); |
send(cmd); |
626 |
send(cmd); |
FTPResponse response = getResponse(); |
627 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
628 |
switch (response.getCode()) |
{ |
629 |
{ |
case 213: |
630 |
case 213: |
size = Integer.parseInt(response.getMessage()); |
631 |
size = Integer.parseInt(response.getMessage()); |
break; |
632 |
break; |
case 550: // File not found |
633 |
case 550: // File not found |
default: |
634 |
default: |
throw new FTPException(response); |
635 |
throw new FTPException(response); |
} |
636 |
} |
*/ |
637 |
*/ |
String cmd = |
638 |
String cmd = new StringBuffer(RETR) |
new StringBuffer(RETR).append(' ').append(filename).toString(); |
639 |
.append(' ') |
send(cmd); |
640 |
.append(filename) |
FTPResponse response = getResponse(); |
641 |
.toString(); |
switch (response.getCode()) |
642 |
send(cmd); |
{ |
643 |
FTPResponse response = getResponse(); |
case 125: // Data connection already open; transfer starting |
644 |
switch (response.getCode()) |
case 150: // File status okay; about to open data connection |
645 |
{ |
return dtp.getInputStream(); |
646 |
case 125: // Data connection already open; transfer starting |
default:throw new FTPException(response); |
647 |
case 150: // File status okay; about to open data connection |
} |
648 |
return dtp.getInputStream(); |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
649 |
|
|
650 |
/** |
/** |
651 |
* Returns a stream for uploading a file. |
* Returns a stream for uploading a file. |
652 |
* If a file with the same filename already exists on the server, it will |
* If a file with the same filename already exists on the server, it will |
653 |
* be overwritten. |
* be overwritten. |
654 |
* @param filename the name of the file to save the content as |
* @param filename the name of the file to save the content as |
655 |
* @return an OutputStream to write the file data to |
* @return an OutputStream to write the file data to |
656 |
*/ |
*/ |
657 |
public OutputStream store(String filename) |
public OutputStream store(String filename) throws IOException |
658 |
throws IOException |
{ |
659 |
{ |
if (dtp == null || transferMode == MODE_STREAM) |
660 |
if (dtp==null || transferMode==MODE_STREAM) |
initialiseDTP(); |
661 |
initialiseDTP(); |
String cmd = |
662 |
String cmd = new StringBuffer(STOR) |
new StringBuffer(STOR).append(' ').append(filename).toString(); |
663 |
.append(' ') |
send(cmd); |
664 |
.append(filename) |
FTPResponse response = getResponse(); |
665 |
.toString(); |
switch (response.getCode()) |
666 |
send(cmd); |
{ |
667 |
FTPResponse response = getResponse(); |
case 125: // Data connection already open; transfer starting |
668 |
switch (response.getCode()) |
case 150: // File status okay; about to open data connection |
669 |
{ |
return dtp.getOutputStream(); |
670 |
case 125: // Data connection already open; transfer starting |
default:throw new FTPException(response); |
671 |
case 150: // File status okay; about to open data connection |
} |
672 |
return dtp.getOutputStream(); |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
673 |
|
|
674 |
/** |
/** |
675 |
* Returns a stream for uploading a file. |
* Returns a stream for uploading a file. |
676 |
* If a file with the same filename already exists on the server, the |
* If a file with the same filename already exists on the server, the |
677 |
* content specified will be appended to the existing file. |
* content specified will be appended to the existing file. |
678 |
* @param filename the name of the file to save the content as |
* @param filename the name of the file to save the content as |
679 |
* @return an OutputStream to write the file data to |
* @return an OutputStream to write the file data to |
680 |
*/ |
*/ |
681 |
public OutputStream append(String filename) |
public OutputStream append(String filename) throws IOException |
682 |
throws IOException |
{ |
683 |
{ |
if (dtp == null || transferMode == MODE_STREAM) |
684 |
if (dtp==null || transferMode==MODE_STREAM) |
initialiseDTP(); |
685 |
initialiseDTP(); |
String cmd = |
686 |
String cmd = new StringBuffer(APPE) |
new StringBuffer(APPE).append(' ').append(filename).toString(); |
687 |
.append(' ') |
send(cmd); |
688 |
.append(filename) |
FTPResponse response = getResponse(); |
689 |
.toString(); |
switch (response.getCode()) |
690 |
send(cmd); |
{ |
691 |
FTPResponse response = getResponse(); |
case 125: // Data connection already open; transfer starting |
692 |
switch (response.getCode()) |
case 150: // File status okay; about to open data connection |
693 |
{ |
return dtp.getOutputStream(); |
694 |
case 125: // Data connection already open; transfer starting |
default:throw new FTPException(response); |
695 |
case 150: // File status okay; about to open data connection |
} |
696 |
return dtp.getOutputStream(); |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
697 |
|
|
698 |
/** |
/** |
699 |
* This command may be required by some servers to reserve sufficient |
* This command may be required by some servers to reserve sufficient |
700 |
* storage to accommodate the new file to be transferred. |
* storage to accommodate the new file to be transferred. |
701 |
* It should be immediately followed by a <code>store</code> or |
* It should be immediately followed by a <code>store</code> or |
702 |
* <code>append</code>. |
* <code>append</code>. |
703 |
* @param size the number of bytes of storage to allocate |
* @param size the number of bytes of storage to allocate |
704 |
*/ |
*/ |
705 |
public void allocate(long size) |
public void allocate(long size) throws IOException |
706 |
throws IOException |
{ |
707 |
{ |
String cmd = new StringBuffer(ALLO).append(' ').append(size).toString(); |
708 |
String cmd = new StringBuffer(ALLO) |
send(cmd); |
709 |
.append(' ') |
FTPResponse response = getResponse(); |
710 |
.append(size) |
switch (response.getCode()) |
711 |
.toString(); |
{ |
712 |
send(cmd); |
case 200: // OK |
713 |
FTPResponse response = getResponse(); |
case 202: // Superfluous |
714 |
switch (response.getCode()) |
break; |
715 |
{ |
default:throw new FTPException(response); |
716 |
case 200: // OK |
} |
717 |
case 202: // Superfluous |
} |
|
break; |
|
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
718 |
|
|
719 |
/** |
/** |
720 |
* Renames a file. |
* Renames a file. |
721 |
* @param oldName the current name of the file |
* @param oldName the current name of the file |
722 |
* @param newName the new name |
* @param newName the new name |
723 |
* @return true if successful, false otherwise |
* @return true if successful, false otherwise |
724 |
*/ |
*/ |
725 |
public boolean rename(String oldName, String newName) |
public boolean rename(String oldName, String newName) throws IOException |
726 |
throws IOException |
{ |
727 |
{ |
String cmd = |
728 |
String cmd = new StringBuffer(RNFR) |
new StringBuffer(RNFR).append(' ').append(oldName).toString(); |
729 |
.append(' ') |
send(cmd); |
730 |
.append(oldName) |
FTPResponse response = getResponse(); |
731 |
.toString(); |
switch (response.getCode()) |
732 |
send(cmd); |
{ |
733 |
FTPResponse response = getResponse(); |
case 450: // File unavailable |
734 |
switch (response.getCode()) |
case 550: // File not found |
735 |
{ |
return false; |
736 |
case 450: // File unavailable |
case 350: // Pending |
737 |
case 550: // File not found |
break; |
738 |
return false; |
default:throw new FTPException(response); |
739 |
case 350: // Pending |
} |
740 |
break; |
cmd = new StringBuffer(RNTO).append(' ').append(newName).toString(); |
741 |
default: |
send(cmd); |
742 |
throw new FTPException(response); |
response = getResponse(); |
743 |
} |
switch (response.getCode()) |
744 |
cmd = new StringBuffer(RNTO) |
{ |
745 |
.append(' ') |
case 250: // OK |
746 |
.append(newName) |
return true; |
747 |
.toString(); |
case 450: |
748 |
send(cmd); |
case 550: |
749 |
response = getResponse(); |
return false; |
750 |
switch (response.getCode()) |
default: |
751 |
{ |
throw new FTPException(response); |
752 |
case 250: // OK |
} |
753 |
return true; |
} |
|
case 450: |
|
|
case 550: |
|
|
return false; |
|
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
754 |
|
|
755 |
/** |
/** |
756 |
* Aborts the transfer in progress. |
* Aborts the transfer in progress. |
757 |
* @return true if a transfer was in progress, false otherwise |
* @return true if a transfer was in progress, false otherwise |
758 |
*/ |
*/ |
759 |
public boolean abort() |
public boolean abort() throws IOException |
760 |
throws IOException |
{ |
761 |
{ |
send(ABOR); |
762 |
send(ABOR); |
FTPResponse response = getResponse(); |
763 |
FTPResponse response = getResponse(); |
// Abort client DTP |
764 |
// Abort client DTP |
if (dtp != null) |
765 |
if (dtp!=null) |
dtp.abort(); |
766 |
dtp.abort(); |
switch (response.getCode()) |
767 |
switch (response.getCode()) |
{ |
768 |
{ |
case 226: // successful abort |
769 |
case 226: // successful abort |
return false; |
770 |
return false; |
case 426: // interrupted |
771 |
case 426: // interrupted |
response = getResponse(); |
772 |
response = getResponse(); |
if (response.getCode() == 226) |
773 |
if (response.getCode()==226) |
return true; |
774 |
return true; |
default:throw new FTPException(response); |
775 |
default: |
} |
776 |
throw new FTPException(response); |
} |
|
} |
|
|
} |
|
777 |
|
|
778 |
/** |
/** |
779 |
* Causes the file specified to be deleted at the server site. |
* Causes the file specified to be deleted at the server site. |
780 |
* @param filename the file to delete |
* @param filename the file to delete |
781 |
*/ |
*/ |
782 |
public boolean delete(String filename) |
public boolean delete(String filename) throws IOException |
783 |
throws IOException |
{ |
784 |
{ |
String cmd = |
785 |
String cmd = new StringBuffer(DELE) |
new StringBuffer(DELE).append(' ').append(filename).toString(); |
786 |
.append(' ') |
send(cmd); |
787 |
.append(filename) |
FTPResponse response = getResponse(); |
788 |
.toString(); |
switch (response.getCode()) |
789 |
send(cmd); |
{ |
790 |
FTPResponse response = getResponse(); |
case 250: // OK |
791 |
switch (response.getCode()) |
return true; |
792 |
{ |
case 450: // File unavailable |
793 |
case 250: // OK |
case 550: // File not found |
794 |
return true; |
return false; |
795 |
case 450: // File unavailable |
default:throw new FTPException(response); |
796 |
case 550: // File not found |
} |
797 |
return false; |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
798 |
|
|
799 |
/** |
/** |
800 |
* Causes the directory specified to be deleted. |
* Causes the directory specified to be deleted. |
801 |
* This may be an absolute or relative pathname. |
* This may be an absolute or relative pathname. |
802 |
* @param pathname the directory to delete |
* @param pathname the directory to delete |
803 |
*/ |
*/ |
804 |
public boolean removeDirectory(String pathname) |
public boolean removeDirectory(String pathname) throws IOException |
805 |
throws IOException |
{ |
806 |
{ |
String cmd = |
807 |
String cmd = new StringBuffer(RMD) |
new StringBuffer(RMD).append(' ').append(pathname).toString(); |
808 |
.append(' ') |
send(cmd); |
809 |
.append(pathname) |
FTPResponse response = getResponse(); |
810 |
.toString(); |
switch (response.getCode()) |
811 |
send(cmd); |
{ |
812 |
FTPResponse response = getResponse(); |
case 250: // OK |
813 |
switch (response.getCode()) |
return true; |
814 |
{ |
case 550: // File not found |
815 |
case 250: // OK |
return false; |
816 |
return true; |
default:throw new FTPException(response); |
817 |
case 550: // File not found |
} |
818 |
return false; |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
819 |
|
|
820 |
/** |
/** |
821 |
* Causes the directory specified to be created at the server site. |
* Causes the directory specified to be created at the server site. |
822 |
* This may be an absolute or relative pathname. |
* This may be an absolute or relative pathname. |
823 |
* @param pathname the directory to create |
* @param pathname the directory to create |
824 |
*/ |
*/ |
825 |
public boolean makeDirectory(String pathname) |
public boolean makeDirectory(String pathname) throws IOException |
826 |
throws IOException |
{ |
827 |
{ |
String cmd = |
828 |
String cmd = new StringBuffer(MKD) |
new StringBuffer(MKD).append(' ').append(pathname).toString(); |
829 |
.append(' ') |
send(cmd); |
830 |
.append(pathname) |
FTPResponse response = getResponse(); |
831 |
.toString(); |
switch (response.getCode()) |
832 |
send(cmd); |
{ |
833 |
FTPResponse response = getResponse(); |
case 257: // Directory created |
834 |
switch (response.getCode()) |
return true; |
835 |
{ |
case 550: // File not found |
836 |
case 257: // Directory created |
return false; |
837 |
return true; |
default:throw new FTPException(response); |
838 |
case 550: // File not found |
} |
839 |
return false; |
} |
|
default: |
|
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
840 |
|
|
841 |
/** |
/** |
842 |
* Returns the current working directory. |
* Returns the current working directory. |
843 |
*/ |
*/ |
844 |
public String getWorkingDirectory() |
public String getWorkingDirectory() throws IOException |
845 |
throws IOException |
{ |
846 |
{ |
send(PWD); |
847 |
send(PWD); |
FTPResponse response = getResponse(); |
848 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
849 |
switch (response.getCode()) |
{ |
850 |
{ |
case 257: |
851 |
case 257: |
String message = response.getMessage(); |
852 |
String message = response.getMessage(); |
if (message.charAt(0) == '"') |
853 |
if (message.charAt(0)=='"') |
{ |
854 |
{ |
int end = message.indexOf('"', 1); |
855 |
int end = message.indexOf('"', 1); |
if (end == -1) |
856 |
if (end==-1) |
throw new ProtocolException(message); |
857 |
throw new ProtocolException(message); |
return message.substring(1, end); |
858 |
return message.substring(1, end); |
} |
859 |
} |
else |
860 |
else |
{ |
861 |
{ |
int end = message.indexOf(' '); |
862 |
int end = message.indexOf(' '); |
if (end == -1) |
863 |
if (end==-1) |
return message; |
864 |
return message; |
else |
865 |
else |
return message.substring(0, end); |
866 |
return message.substring(0, end); |
} |
867 |
} |
default: |
868 |
default: |
throw new FTPException(response); |
869 |
throw new FTPException(response); |
} |
870 |
} |
} |
|
} |
|
871 |
|
|
872 |
/** |
/** |
873 |
* Returns a listing of information about the specified pathname. |
* Returns a listing of information about the specified pathname. |
874 |
* If the pathname specifies a directory or other group of files, the |
* If the pathname specifies a directory or other group of files, the |
875 |
* server should transfer a list of files in the specified directory. |
* server should transfer a list of files in the specified directory. |
878 |
* current working or default directory. |
* current working or default directory. |
879 |
* @param pathname the context pathname, or null |
* @param pathname the context pathname, or null |
880 |
*/ |
*/ |
881 |
public InputStream list(String pathname) |
public InputStream list(String pathname) throws IOException |
882 |
throws IOException |
{ |
883 |
{ |
if (dtp == null || transferMode == MODE_STREAM) |
884 |
if (dtp==null || transferMode==MODE_STREAM) |
initialiseDTP(); |
885 |
initialiseDTP(); |
if (pathname == null) |
886 |
if (pathname==null) |
send(LIST); |
887 |
send(LIST); |
else |
888 |
else |
{ |
889 |
{ |
String cmd = |
890 |
String cmd = new StringBuffer(LIST) |
new StringBuffer(LIST).append(' ').append(pathname).toString(); |
891 |
.append(' ') |
send(cmd); |
892 |
.append(pathname) |
} |
893 |
.toString(); |
FTPResponse response = getResponse(); |
894 |
send(cmd); |
switch (response.getCode()) |
895 |
} |
{ |
896 |
FTPResponse response = getResponse(); |
case 125: // Data connection already open; transfer starting |
897 |
switch (response.getCode()) |
case 150: // File status okay; about to open data connection |
898 |
{ |
return dtp.getInputStream(); |
899 |
case 125: // Data connection already open; transfer starting |
default: |
900 |
case 150: // File status okay; about to open data connection |
throw new FTPException(response); |
901 |
return dtp.getInputStream(); |
} |
902 |
default: |
} |
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
903 |
|
|
904 |
/** |
/** |
905 |
* Returns a directory listing. The pathname should specify a |
* Returns a directory listing. The pathname should specify a |
906 |
* directory or other system-specific file group descriptor; a null |
* directory or other system-specific file group descriptor; a null |
907 |
* argument implies the user's current working or default directory. |
* argument implies the user's current working or default directory. |
908 |
* @param pathname the directory pathname, or null |
* @param pathname the directory pathname, or null |
909 |
* @return a list of filenames (strings) |
* @return a list of filenames (strings) |
910 |
*/ |
*/ |
911 |
public List nameList(String pathname) |
public List nameList(String pathname) throws IOException |
912 |
throws IOException |
{ |
913 |
{ |
if (dtp == null || transferMode == MODE_STREAM) |
914 |
if (dtp==null || transferMode==MODE_STREAM) |
initialiseDTP(); |
915 |
initialiseDTP(); |
if (pathname == null) |
916 |
if (pathname==null) |
send(NLST); |
917 |
send(NLST); |
else |
918 |
else |
{ |
919 |
{ |
String cmd = |
920 |
String cmd = new StringBuffer(NLST) |
new StringBuffer(NLST).append(' ').append(pathname).toString(); |
921 |
.append(' ') |
send(cmd); |
922 |
.append(pathname) |
} |
923 |
.toString(); |
FTPResponse response = getResponse(); |
924 |
send(cmd); |
switch (response.getCode()) |
925 |
} |
{ |
926 |
FTPResponse response = getResponse(); |
case 125: // Data connection already open; transfer starting |
927 |
switch (response.getCode()) |
case 150: // File status okay; about to open data connection |
928 |
{ |
InputStream in = dtp.getInputStream(); |
929 |
case 125: // Data connection already open; transfer starting |
in = new BufferedInputStream(in); |
930 |
case 150: // File status okay; about to open data connection |
in = new CRLFInputStream(in); // TODO ensure that TYPE is correct |
931 |
InputStream in = dtp.getInputStream(); |
LineInputStream li = new LineInputStream(in); |
932 |
in = new BufferedInputStream(in); |
List ret = new ArrayList(); |
933 |
in = new CRLFInputStream(in); // TODO ensure that TYPE is correct |
for (String line = li.readLine(); line != null; line = li.readLine()) |
934 |
LineInputStream li = new LineInputStream(in); |
ret.add(line); |
935 |
List ret = new ArrayList(); |
li.close(); |
936 |
for (String line = li.readLine(); line!=null; line = li.readLine()) |
return ret; |
937 |
ret.add(line); |
default: |
938 |
li.close(); |
throw new FTPException(response); |
939 |
return ret; |
} |
940 |
default: |
} |
|
throw new FTPException(response); |
|
|
} |
|
|
} |
|
941 |
|
|
942 |
/** |
/** |
943 |
* Returns the type of operating system at the server. |
* Returns the type of operating system at the server. |
944 |
*/ |
*/ |
945 |
public String system() |
public String system() throws IOException |
946 |
throws IOException |
{ |
947 |
{ |
send(SYST); |
948 |
send(SYST); |
FTPResponse response = getResponse(); |
949 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
950 |
switch (response.getCode()) |
{ |
951 |
{ |
case 215: |
952 |
case 215: |
String message = response.getMessage(); |
953 |
String message = response.getMessage(); |
int end = message.indexOf(' '); |
954 |
int end = message.indexOf(' '); |
if (end == -1) |
955 |
if (end==-1) |
return message; |
956 |
return message; |
else |
957 |
else |
return message.substring(0, end); |
958 |
return message.substring(0, end); |
default:throw new FTPException(response); |
959 |
default: |
} |
960 |
throw new FTPException(response); |
} |
|
} |
|
|
} |
|
961 |
|
|
962 |
/** |
/** |
963 |
* Does nothing. |
* Does nothing. |
964 |
* This method can be used to ensure that the connection does not time |
* This method can be used to ensure that the connection does not time |
965 |
* out. |
* out. |
966 |
*/ |
*/ |
967 |
public void noop() |
public void noop() throws IOException |
968 |
throws IOException |
{ |
969 |
{ |
send(NOOP); |
970 |
send(NOOP); |
FTPResponse response = getResponse(); |
971 |
FTPResponse response = getResponse(); |
switch (response.getCode()) |
972 |
switch (response.getCode()) |
{ |
973 |
{ |
case 200: |
974 |
case 200: |
break; |
975 |
break; |
default:throw new FTPException(response); |
976 |
default: |
} |
977 |
throw new FTPException(response); |
} |
|
} |
|
|
} |
|
978 |
|
|
979 |
// -- I/O -- |
// -- I/O -- |
980 |
|
|
981 |
/** |
/** |
982 |
* Sends the specified command line to the server. |
* Sends the specified command line to the server. |
983 |
* The CRLF sequence is automatically appended. |
* The CRLF sequence is automatically appended. |
984 |
* @param cmd the command line to send |
* @param cmd the command line to send |
985 |
*/ |
*/ |
986 |
protected void send(String cmd) |
protected void send(String cmd) throws IOException |
987 |
throws IOException |
{ |
988 |
{ |
byte[] data = cmd.getBytes(US_ASCII); |
989 |
byte[] data = cmd.getBytes(US_ASCII); |
out.write(data); |
990 |
out.write(data); |
out.write(CRLF); |
991 |
out.write(CRLF); |
out.flush(); |
992 |
out.flush(); |
} |
|
} |
|
993 |
|
|
994 |
/** |
/** |
995 |
* Reads the next response from the server. |
* Reads the next response from the server. |
996 |
* If the server sends the "transfer complete" code, this is handled here, |
* If the server sends the "transfer complete" code, this is handled here, |
997 |
* and the next response is passed to the caller. |
* and the next response is passed to the caller. |
998 |
*/ |
*/ |
999 |
protected FTPResponse getResponse() |
protected FTPResponse getResponse() throws IOException |
1000 |
throws IOException |
{ |
1001 |
{ |
FTPResponse response = readResponse(); |
1002 |
FTPResponse response = readResponse(); |
if (response.getCode() == 226) |
1003 |
if (response.getCode()==226) |
{ |
1004 |
{ |
if (dtp != null) |
1005 |
if (dtp!=null) |
dtp.transferComplete(); |
1006 |
dtp.transferComplete(); |
response = readResponse(); |
1007 |
response = readResponse(); |
} |
1008 |
} |
return response; |
1009 |
return response; |
} |
|
} |
|
1010 |
|
|
1011 |
/** |
/** |
1012 |
* Reads and parses the next response from the server. |
* Reads and parses the next response from the server. |
1013 |
*/ |
*/ |
1014 |
protected FTPResponse readResponse() |
protected FTPResponse readResponse() throws IOException |
1015 |
throws IOException |
{ |
1016 |
{ |
String line = in.readLine(); |
1017 |
String line = in.readLine(); |
if (line == null) |
1018 |
if (line==null) |
throw new ProtocolException("EOF"); |
1019 |
throw new ProtocolException("EOF"); |
if (line.length() < 4) |
1020 |
if (line.length()<4) |
throw new ProtocolException(line); |
1021 |
throw new ProtocolException(line); |
int code = parseCode(line); |
1022 |
int code = parseCode(line); |
if (code == -1) |
1023 |
if (code==-1) |
throw new ProtocolException(line); |
1024 |
throw new ProtocolException(line); |
char c = line.charAt(3); |
1025 |
char c = line.charAt(3); |
if (c == ' ') |
1026 |
if (c==' ') |
return new FTPResponse(code, line.substring(4)); |
1027 |
return new FTPResponse(code, line.substring(4)); |
else if (c == '-') |
1028 |
else if (c=='-') |
{ |
1029 |
{ |
StringBuffer buf = new StringBuffer(line.substring(4)); |
1030 |
StringBuffer buf = new StringBuffer(line.substring(4)); |
buf.append('\n'); |
1031 |
buf.append('\n'); |
while (true) |
1032 |
while (true) |
{ |
1033 |
{ |
line = in.readLine(); |
1034 |
line = in.readLine(); |
if (line == null) |
1035 |
if (line==null) |
throw new ProtocolException("EOF"); |
1036 |
throw new ProtocolException("EOF"); |
if (line.length() >= 4 && line.charAt(3) == ' ' |
1037 |
if (line.length()>=4 && line.charAt(3)==' ' && parseCode(line)==code) |
&& parseCode(line) == code) |
1038 |
return new FTPResponse(code, line.substring(4), buf.toString()); |
return new FTPResponse(code, line.substring(4), buf.toString()); |
1039 |
else |
else |
1040 |
{ |
{ |
1041 |
buf.append(line); |
buf.append(line); |
1042 |
buf.append('\n'); |
buf.append('\n'); |
1043 |
} |
} |
1044 |
|
|
1045 |
} |
} |
1046 |
} |
} |
1047 |
else |
else |
1048 |
throw new ProtocolException(line); |
throw new ProtocolException(line); |
1049 |
} |
} |
1050 |
|
|
1051 |
/* |
/* |
1052 |
* Parses the 3-digit numeric code at the beginning of the given line. |
* Parses the 3-digit numeric code at the beginning of the given line. |
1053 |
* Returns -1 on failure. |
* Returns -1 on failure. |
1054 |
*/ |
*/ |
1055 |
static final int parseCode(String line) |
static final int parseCode(String line) |
1056 |
{ |
{ |
1057 |
char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) }; |
char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) }; |
1058 |
int ret = 0; |
int ret = 0; |
1059 |
for (int i=0; i<3; i++) |
for (int i = 0; i < 3; i++) |
1060 |
{ |
{ |
1061 |
int digit = ((int)c[i])-0x30; |
int digit = ((int) c[i]) - 0x30; |
1062 |
if (digit<0 || digit>9) |
if (digit < 0 || digit > 9) |
1063 |
return -1; |
return -1; |
1064 |
// Computing integer powers is way too expensive in Java! |
// Computing integer powers is way too expensive in Java! |
1065 |
switch (i) |
switch (i) |
1066 |
{ |
{ |
1067 |
case 0: |
case 0: |
1068 |
ret += (100*digit); |
ret += (100 * digit); |
1069 |
break; |
break; |
1070 |
case 1: |
case 1: |
1071 |
ret += (10*digit); |
ret += (10 * digit); |
1072 |
break; |
break; |
1073 |
case 2: |
case 2: |
1074 |
ret += digit; |
ret += digit; |
1075 |
break; |
break; |
1076 |
} |
} |
1077 |
} |
} |
1078 |
return ret; |
return ret; |
1079 |
} |
} |
1080 |
|
|
1081 |
} |
} |