1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.net.ftp;
18 import java.io.BufferedInputStream;
19 import java.io.BufferedOutputStream;
20 import java.io.BufferedReader;
21 import java.io.BufferedWriter;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.OutputStream;
26 import java.io.OutputStreamWriter;
27 import java.net.Inet6Address;
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.net.ServerSocket;
31 import java.net.Socket;
32 import java.net.SocketException;
33 import java.net.SocketTimeoutException;
34 import java.net.UnknownHostException;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.Locale;
39 import java.util.Properties;
40 import java.util.Random;
41 import java.util.Set;
42
43 import org.apache.commons.net.MalformedServerReplyException;
44 import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
45 import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
46 import org.apache.commons.net.ftp.parser.MLSxEntryParser;
47 import org.apache.commons.net.io.CRLFLineReader;
48 import org.apache.commons.net.io.CopyStreamAdapter;
49 import org.apache.commons.net.io.CopyStreamEvent;
50 import org.apache.commons.net.io.CopyStreamListener;
51 import org.apache.commons.net.io.FromNetASCIIInputStream;
52 import org.apache.commons.net.io.ToNetASCIIOutputStream;
53 import org.apache.commons.net.io.Util;
54
55 /**
56 * FTPClient encapsulates all the functionality necessary to store and
57 * retrieve files from an FTP server. This class takes care of all
58 * low level details of interacting with an FTP server and provides
59 * a convenient higher level interface. As with all classes derived
60 * from {@link org.apache.commons.net.SocketClient},
61 * you must first connect to the server with
62 * {@link org.apache.commons.net.SocketClient#connect connect }
63 * before doing anything, and finally
64 * {@link org.apache.commons.net.SocketClient#disconnect disconnect }
65 * after you're completely finished interacting with the server.
66 * Then you need to check the FTP reply code to see if the connection
67 * was successful. For example:
68 * <pre>
69 * FTPClient ftp = new FTPClient();
70 * FTPClientConfig config = new FTPClientConfig();
71 * config.setXXX(YYY); // change required options
72 * ftp.configure(config );
73 * boolean error = false;
74 * try {
75 * int reply;
76 * ftp.connect("ftp.foobar.com");
77 * System.out.println("Connected to " + server + ".");
78 * System.out.print(ftp.getReplyString());
79 *
80 * // After connection attempt, you should check the reply code to verify
81 * // success.
82 * reply = ftp.getReplyCode();
83 *
84 * if(!FTPReply.isPositiveCompletion(reply)) {
85 * ftp.disconnect();
86 * System.err.println("FTP server refused connection.");
87 * System.exit(1);
88 * }
89 * ... // transfer files
90 * ftp.logout();
91 * } catch(IOException e) {
92 * error = true;
93 * e.printStackTrace();
94 * } finally {
95 * if(ftp.isConnected()) {
96 * try {
97 * ftp.disconnect();
98 * } catch(IOException ioe) {
99 * // do nothing
100 * }
101 * }
102 * System.exit(error ? 1 : 0);
103 * }
104 * </pre>
105 * <p>
106 * Immediately after connecting is the only real time you need to check the
107 * reply code (because connect is of type void). The convention for all the
108 * FTP command methods in FTPClient is such that they either return a
109 * boolean value or some other value.
110 * The boolean methods return true on a successful completion reply from
111 * the FTP server and false on a reply resulting in an error condition or
112 * failure. The methods returning a value other than boolean return a value
113 * containing the higher level data produced by the FTP command, or null if a
114 * reply resulted in an error condition or failure. If you want to access
115 * the exact FTP reply code causing a success or failure, you must call
116 * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after
117 * a success or failure.
118 * <p>
119 * The default settings for FTPClient are for it to use
120 * <code> FTP.ASCII_FILE_TYPE </code>,
121 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
122 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
123 * <code> FTP.FILE_STRUCTURE </code>. The only file types directly supported
124 * are <code> FTP.ASCII_FILE_TYPE </code> and
125 * <code> FTP.BINARY_FILE_TYPE </code>. Because there are at least 4
126 * different EBCDIC encodings, we have opted not to provide direct support
127 * for EBCDIC. To transfer EBCDIC and other unsupported file types you
128 * must create your own filter InputStreams and OutputStreams and wrap
129 * them around the streams returned or required by the FTPClient methods.
130 * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII}
131 * filter streams to provide transparent handling of ASCII files. We will
132 * consider incorporating EBCDIC support if there is enough demand.
133 * <p>
134 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
135 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
136 * <code> FTP.FILE_STRUCTURE </code> are the only supported formats,
137 * transfer modes, and file structures.
138 * <p>
139 * Because the handling of sockets on different platforms can differ
140 * significantly, the FTPClient automatically issues a new PORT (or EPRT) command
141 * prior to every transfer requiring that the server connect to the client's
142 * data port. This ensures identical problem-free behavior on Windows, Unix,
143 * and Macintosh platforms. Additionally, it relieves programmers from
144 * having to issue the PORT (or EPRT) command themselves and dealing with platform
145 * dependent issues.
146 * <p>
147 * Additionally, for security purposes, all data connections to the
148 * client are verified to ensure that they originated from the intended
149 * party (host and port). If a data connection is initiated by an unexpected
150 * party, the command will close the socket and throw an IOException. You
151 * may disable this behavior with
152 * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}.
153 * <p>
154 * You should keep in mind that the FTP server may choose to prematurely
155 * close a connection if the client has been idle for longer than a
156 * given time period (usually 900 seconds). The FTPClient class will detect a
157 * premature FTP server connection closing when it receives a
158 * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE }
159 * response to a command.
160 * When that occurs, the FTP class method encountering that reply will throw
161 * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException}
162 * .
163 * <code>FTPConnectionClosedException</code>
164 * is a subclass of <code> IOException </code> and therefore need not be
165 * caught separately, but if you are going to catch it separately, its
166 * catch block must appear before the more general <code> IOException </code>
167 * catch block. When you encounter an
168 * {@link org.apache.commons.net.ftp.FTPConnectionClosedException}
169 * , you must disconnect the connection with
170 * {@link #disconnect disconnect() } to properly clean up the
171 * system resources used by FTPClient. Before disconnecting, you may check the
172 * last reply code and text with
173 * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode },
174 * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString },
175 * and
176 * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}.
177 * You may avoid server disconnections while the client is idle by
178 * periodically sending NOOP commands to the server.
179 * <p>
180 * Rather than list it separately for each method, we mention here that
181 * every method communicating with the server and throwing an IOException
182 * can also throw a
183 * {@link org.apache.commons.net.MalformedServerReplyException}
184 * , which is a subclass
185 * of IOException. A MalformedServerReplyException will be thrown when
186 * the reply received from the server deviates enough from the protocol
187 * specification that it cannot be interpreted in a useful manner despite
188 * attempts to be as lenient as possible.
189 * <p>
190 * Listing API Examples
191 * Both paged and unpaged examples of directory listings are available,
192 * as follows:
193 * <p>
194 * Unpaged (whole list) access, using a parser accessible by auto-detect:
195 * <pre>
196 * FTPClient f = new FTPClient();
197 * f.connect(server);
198 * f.login(username, password);
199 * FTPFile[] files = f.listFiles(directory);
200 * </pre>
201 * <p>
202 * Paged access, using a parser not accessible by auto-detect. The class
203 * defined in the first parameter of initateListParsing should be derived
204 * from org.apache.commons.net.FTPFileEntryParser:
205 * <pre>
206 * FTPClient f = new FTPClient();
207 * f.connect(server);
208 * f.login(username, password);
209 * FTPListParseEngine engine =
210 * f.initiateListParsing("com.whatever.YourOwnParser", directory);
211 *
212 * while (engine.hasNext()) {
213 * FTPFile[] files = engine.getNext(25); // "page size" you want
214 * //do whatever you want with these files, display them, etc.
215 * //expensive FTPFile objects not created until needed.
216 * }
217 * </pre>
218 * <p>
219 * Paged access, using a parser accessible by auto-detect:
220 * <pre>
221 * FTPClient f = new FTPClient();
222 * f.connect(server);
223 * f.login(username, password);
224 * FTPListParseEngine engine = f.initiateListParsing(directory);
225 *
226 * while (engine.hasNext()) {
227 * FTPFile[] files = engine.getNext(25); // "page size" you want
228 * //do whatever you want with these files, display them, etc.
229 * //expensive FTPFile objects not created until needed.
230 * }
231 * </pre>
232 * <p>
233 * For examples of using FTPClient on servers whose directory listings
234 * <ul>
235 * <li>use languages other than English</li>
236 * <li>use date formats other than the American English "standard" <code>MM d yyyy</code></li>
237 * <li>are in different timezones and you need accurate timestamps for dependency checking
238 * as in Ant</li>
239 * </ul>see {@link FTPClientConfig FTPClientConfig}.
240 * <p>
241 * <b>Control channel keep-alive feature</b>:<br/>
242 * During file transfers, the data connection is busy, but the control connection is idle.
243 * FTP servers know that the control connection is in use, so won't close it through lack of activity,
244 * but it's a lot harder for network routers to know that the control and data connections are associated
245 * with each other.
246 * Some routers may treat the control connection as idle, and disconnect it if the transfer over the data
247 * connection takes longer than the allowable idle time for the router.
248 * <br/>
249 * One solution to this is to send a safe command (i.e. NOOP) over the control connection to reset the router's
250 * idle timer. This is enabled as follows:
251 * <pre>
252 * ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes
253 * </pre>
254 * This will cause the file upload/download methods to send a NOOP approximately every 5 minutes.
255 * <p>
256 * The implementation currently uses a {@link CopyStreamListener} which is passed to the
257 * {@link Util#copyStream(InputStream, OutputStream, int, long, CopyStreamListener, boolean)}
258 * method, so the timing is partially dependent on how long each block transfer takes.
259 * <p>
260 * <b>Note:</b> this does not apply to the methods where the user is responsible for writing or reading
261 * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)}
262 * and the other xxxFileStream methods
263 * <p>
264 *
265 * @see #FTP_SYSTEM_TYPE
266 * @see #SYSTEM_TYPE_PROPERTIES
267 * @see FTP
268 * @see FTPConnectionClosedException
269 * @see FTPFileEntryParser
270 * @see FTPFileEntryParserFactory
271 * @see DefaultFTPFileEntryParserFactory
272 * @see FTPClientConfig
273 *
274 * @see org.apache.commons.net.MalformedServerReplyException
275 */
276 public class FTPClient extends FTP
277 implements Configurable
278 {
279 /**
280 * The system property ({@value}) which can be used to override the system type.<br/>
281 * If defined, the value will be used to create any automatically created parsers.
282 *
283 * @since 3.0
284 */
285 public static final String FTP_SYSTEM_TYPE = "org.apache.commons.net.ftp.systemType";
286
287 /**
288 * The system property ({@value}) which can be used as the default system type.<br/>
289 * If defined, the value will be used if the SYST command fails.
290 *
291 * @since 3.1
292 */
293 public static final String FTP_SYSTEM_TYPE_DEFAULT = "org.apache.commons.net.ftp.systemType.default";
294
295 /**
296 * The name of an optional systemType properties file ({@value}), which is loaded
297 * using {@link Class#getResourceAsStream(String)}.<br/>
298 * The entries are the systemType (as determined by {@link FTPClient#getSystemType})
299 * and the values are the replacement type or parserClass, which is passed to
300 * {@link FTPFileEntryParserFactory#createFileEntryParser(String)}.<br/>
301 * For example:
302 * <pre>
303 * Plan 9=Unix
304 * OS410=org.apache.commons.net.ftp.parser.OS400FTPEntryParser
305 * </pre>
306 *
307 * @since 3.0
308 */
309 public static final String SYSTEM_TYPE_PROPERTIES = "/systemType.properties";
310
311 /**
312 * A constant indicating the FTP session is expecting all transfers
313 * to occur between the client (local) and server and that the server
314 * should connect to the client's data port to initiate a data transfer.
315 * This is the default data connection mode when and FTPClient instance
316 * is created.
317 */
318 public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0;
319 /**
320 * A constant indicating the FTP session is expecting all transfers
321 * to occur between two remote servers and that the server
322 * the client is connected to should connect to the other server's
323 * data port to initiate a data transfer.
324 */
325 public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1;
326 /**
327 * A constant indicating the FTP session is expecting all transfers
328 * to occur between the client (local) and server and that the server
329 * is in passive mode, requiring the client to connect to the
330 * server's data port to initiate a transfer.
331 */
332 public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2;
333 /**
334 * A constant indicating the FTP session is expecting all transfers
335 * to occur between two remote servers and that the server
336 * the client is connected to is in passive mode, requiring the other
337 * server to connect to the first server's data port to initiate a data
338 * transfer.
339 */
340 public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3;
341
342 private int __dataConnectionMode;
343 private int __dataTimeout;
344 private int __passivePort;
345 private String __passiveHost;
346 private final Random __random;
347 private int __activeMinPort;
348 private int __activeMaxPort;
349 private InetAddress __activeExternalHost;
350 private InetAddress __reportActiveExternalHost; // overrides __activeExternalHost in EPRT/PORT commands
351 /** The address to bind to on passive connections, if necessary. */
352 private InetAddress __passiveLocalHost;
353
354 private int __fileType;
355 @SuppressWarnings("unused") // fields are written, but currently not read
356 private int __fileFormat;
357 @SuppressWarnings("unused") // field is written, but currently not read
358 private int __fileStructure;
359 @SuppressWarnings("unused") // field is written, but currently not read
360 private int __fileTransferMode;
361 private boolean __remoteVerificationEnabled;
362 private long __restartOffset;
363 private FTPFileEntryParserFactory __parserFactory;
364 private int __bufferSize; // buffersize for buffered data streams
365 private int __sendDataSocketBufferSize;
366 private int __receiveDataSocketBufferSize;
367 private boolean __listHiddenFiles;
368 private boolean __useEPSVwithIPv4; // whether to attempt EPSV with an IPv4 connection
369
370 // __systemName is a cached value that should not be referenced directly
371 // except when assigned in getSystemName and __initDefaults.
372 private String __systemName;
373
374 // __entryParser is a cached value that should not be referenced directly
375 // except when assigned in listFiles(String, String) and __initDefaults.
376 private FTPFileEntryParser __entryParser;
377
378 // Key used to create the parser; necessary to ensure that the parser type is not ignored
379 private String __entryParserKey;
380
381 private FTPClientConfig __configuration;
382
383 // Listener used by store/retrieve methods to handle keepalive
384 private CopyStreamListener __copyStreamListener;
385
386 // How long to wait before sending another control keep-alive message
387 private long __controlKeepAliveTimeout;
388
389 // How long to wait (ms) for keepalive message replies before continuing
390 // Most FTP servers don't seem to support concurrent control and data connection usage
391 private int __controlKeepAliveReplyTimeout=1000;
392
393 /** Pattern for PASV mode responses. Groups: (n,n,n,n),(n),(n) */
394 private static final java.util.regex.Pattern __PARMS_PAT;
395 static {
396 __PARMS_PAT = java.util.regex.Pattern.compile(
397 "(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})");
398 }
399
400 /** Controls the automatic server encoding detection (only UTF-8 supported). */
401 private boolean __autodetectEncoding = false;
402
403 /** Map of FEAT responses. If null, has not been initialised. */
404 private HashMap<String, Set<String>> __featuresMap;
405
406 private static class PropertiesSingleton {
407
408 static final Properties PROPERTIES;
409
410 static {
411 InputStream resourceAsStream = FTPClient.class.getResourceAsStream(SYSTEM_TYPE_PROPERTIES);
412 Properties p = null;
413 if (resourceAsStream != null) {
414 p = new Properties();
415 try {
416 p.load(resourceAsStream);
417 } catch (IOException e) {
418 } finally {
419 try {
420 resourceAsStream.close();
421 } catch (IOException e) {
422 // Ignored
423 }
424 }
425 }
426 PROPERTIES = p;
427 }
428
429 }
430 private static Properties getOverrideProperties(){
431 return PropertiesSingleton.PROPERTIES;
432 }
433
434 /**
435 * Default FTPClient constructor. Creates a new FTPClient instance
436 * with the data connection mode set to
437 * <code> ACTIVE_LOCAL_DATA_CONNECTION_MODE </code>, the file type
438 * set to <code> FTP.ASCII_FILE_TYPE </code>, the
439 * file format set to <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
440 * the file structure set to <code> FTP.FILE_STRUCTURE </code>, and
441 * the transfer mode set to <code> FTP.STREAM_TRANSFER_MODE </code>.
442 * <p>
443 * The list parsing auto-detect feature can be configured to use lenient future
444 * dates (short dates may be up to one day in the future) as follows:
445 * <pre>
446 * FTPClient ftp = new FTPClient();
447 * FTPClientConfig config = new FTPClientConfig();
448 * config.setLenientFutureDates(true);
449 * ftp.configure(config );
450 * </pre>
451 */
452 public FTPClient()
453 {
454 __initDefaults();
455 __dataTimeout = -1;
456 __remoteVerificationEnabled = true;
457 __parserFactory = new DefaultFTPFileEntryParserFactory();
458 __configuration = null;
459 __listHiddenFiles = false;
460 __useEPSVwithIPv4 = false;
461 __random = new Random();
462 __passiveLocalHost = null;
463 }
464
465
466 private void __initDefaults()
467 {
468 __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
469 __passiveHost = null;
470 __passivePort = -1;
471 __activeExternalHost = null;
472 __reportActiveExternalHost = null;
473 __activeMinPort = 0;
474 __activeMaxPort = 0;
475 __fileType = FTP.ASCII_FILE_TYPE;
476 __fileStructure = FTP.FILE_STRUCTURE;
477 __fileFormat = FTP.NON_PRINT_TEXT_FORMAT;
478 __fileTransferMode = FTP.STREAM_TRANSFER_MODE;
479 __restartOffset = 0;
480 __systemName = null;
481 __entryParser = null;
482 __entryParserKey = "";
483 __bufferSize = 0;
484 __featuresMap = null;
485 }
486
487 /**
488 * Parse the pathname from a CWD reply.
489 * <p>
490 * According to RFC959 (http://www.ietf.org/rfc/rfc959.txt),
491 * it should be the same as for MKD i.e.
492 * {@code 257<space>"<directory-name>"[<space>commentary]}
493 * where any double-quotes in {@code <directory-name>} are doubled.
494 * Unlike MKD, the commentary is optional.
495 * <p>
496 * However, see NET-442 for an exception.
497 *
498 * @param reply
499 * @return the pathname, without enclosing quotes,
500 * or the full string after the reply code and space if the syntax is invalid
501 * (i.e. enclosing quotes are missing or embedded quotes are not doubled)
502 */
503 // package protected for access by test cases
504 static String __parsePathname(String reply)
505 {
506 String param = reply.substring(REPLY_CODE_LEN + 1);
507 if (param.startsWith("\"")) {
508 StringBuilder sb = new StringBuilder();
509 boolean quoteSeen = false;
510 // start after initial quote
511 for(int i=1; i < param.length(); i++) {
512 char ch = param.charAt(i);
513 if (ch=='"') {
514 if (quoteSeen) {
515 sb.append(ch);
516 quoteSeen=false;
517 } else {
518 // don't output yet, in case doubled
519 quoteSeen=true;
520 }
521 } else {
522 if (quoteSeen) { // found lone trailing quote within string
523 return sb.toString();
524 }
525 sb.append(ch); // just another character
526 }
527 }
528 if (quoteSeen) { // found lone trailing quote at end of string
529 return sb.toString();
530 }
531 }
532 // malformed reply, return all after reply code and space
533 return param;
534 }
535
536 /**
537 * @since 3.1
538 */
539 protected void _parsePassiveModeReply(String reply)
540 throws MalformedServerReplyException
541 {
542 java.util.regex.Matcher m = __PARMS_PAT.matcher(reply);
543 if (!m.find()) {
544 throw new MalformedServerReplyException(
545 "Could not parse passive host information.\nServer Reply: " + reply);
546 }
547
548 __passiveHost = m.group(1).replace(',', '.'); // Fix up to look like IP address
549
550 try
551 {
552 int oct1 = Integer.parseInt(m.group(2));
553 int oct2 = Integer.parseInt(m.group(3));
554 __passivePort = (oct1 << 8) | oct2;
555 }
556 catch (NumberFormatException e)
557 {
558 throw new MalformedServerReplyException(
559 "Could not parse passive port information.\nServer Reply: " + reply);
560 }
561
562 try {
563 InetAddress host = InetAddress.getByName(__passiveHost);
564 // reply is a local address, but target is not - assume NAT box changed the PASV reply
565 if (host.isSiteLocalAddress()) {
566 InetAddress remote = getRemoteAddress();
567 if (!remote.isSiteLocalAddress()){
568 String hostAddress = remote.getHostAddress();
569 fireReplyReceived(0,
570 "[Replacing site local address "+__passiveHost+" with "+hostAddress+"]\n");
571 __passiveHost = hostAddress;
572 }
573 }
574 } catch (UnknownHostException e) { // Should not happen as we are passing in an IP address
575 throw new MalformedServerReplyException(
576 "Could not parse passive host information.\nServer Reply: " + reply);
577 }
578 }
579
580 protected void _parseExtendedPassiveModeReply(String reply)
581 throws MalformedServerReplyException
582 {
583 reply = reply.substring(reply.indexOf('(') + 1,
584 reply.indexOf(')')).trim();
585
586 char delim1, delim2, delim3, delim4;
587 delim1 = reply.charAt(0);
588 delim2 = reply.charAt(1);
589 delim3 = reply.charAt(2);
590 delim4 = reply.charAt(reply.length()-1);
591
592 if (!(delim1 == delim2) || !(delim2 == delim3)
593 || !(delim3 == delim4)) {
594 throw new MalformedServerReplyException(
595 "Could not parse extended passive host information.\nServer Reply: " + reply);
596 }
597
598 int port;
599 try
600 {
601 port = Integer.parseInt(reply.substring(3, reply.length()-1));
602 }
603 catch (NumberFormatException e)
604 {
605 throw new MalformedServerReplyException(
606 "Could not parse extended passive host information.\nServer Reply: " + reply);
607 }
608
609
610 // in EPSV mode, the passive host address is implicit
611 __passiveHost = getRemoteAddress().getHostAddress();
612 __passivePort = port;
613 }
614
615 private boolean __storeFile(FTPCmd command, String remote, InputStream local)
616 throws IOException
617 {
618 return _storeFile(command.getCommand(), remote, local);
619 }
620
621 /**
622 * @since 3.1
623 */
624 protected boolean _storeFile(String command, String remote, InputStream local)
625 throws IOException
626 {
627 Socket socket = _openDataConnection_(command, remote);
628
629 if (socket == null) {
630 return false;
631 }
632
633 OutputStream output;
634
635 if (__fileType == ASCII_FILE_TYPE) {
636 output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream()));
637 } else {
638 output = getBufferedOutputStream(socket.getOutputStream());
639 }
640
641 CSL csl = null;
642 if (__controlKeepAliveTimeout > 0) {
643 csl = new CSL(this, __controlKeepAliveTimeout, __controlKeepAliveReplyTimeout);
644 }
645
646 // Treat everything else as binary for now
647 try
648 {
649 Util.copyStream(local, output, getBufferSize(),
650 CopyStreamEvent.UNKNOWN_STREAM_SIZE, __mergeListeners(csl),
651 false);
652 }
653 catch (IOException e)
654 {
655 Util.closeQuietly(socket); // ignore close errors here
656 if (csl != null) {
657 csl.cleanUp(); // fetch any outstanding keepalive replies
658 }
659 throw e;
660 }
661
662 output.close(); // ensure the file is fully written
663 socket.close(); // done writing the file
664 if (csl != null) {
665 csl.cleanUp(); // fetch any outstanding keepalive replies
666 }
667 // Get the transfer response
668 boolean ok = completePendingCommand();
669 return ok;
670 }
671
672 private OutputStream __storeFileStream(FTPCmd command, String remote)
673 throws IOException
674 {
675 return _storeFileStream(command.getCommand(), remote);
676 }
677
678 /**
679 * @since 3.1
680 */
681 protected OutputStream _storeFileStream(String command, String remote)
682 throws IOException
683 {
684 Socket socket = _openDataConnection_(command, remote);
685
686 if (socket == null) {
687 return null;
688 }
689
690 OutputStream output = socket.getOutputStream();
691 if (__fileType == ASCII_FILE_TYPE) {
692 // We buffer ascii transfers because the buffering has to
693 // be interposed between ToNetASCIIOutputSream and the underlying
694 // socket output stream. We don't buffer binary transfers
695 // because we don't want to impose a buffering policy on the
696 // programmer if possible. Programmers can decide on their
697 // own if they want to wrap the SocketOutputStream we return
698 // for file types other than ASCII.
699 output = getBufferedOutputStream(output);
700 output = new ToNetASCIIOutputStream(output);
701
702 }
703 return new org.apache.commons.net.io.SocketOutputStream(socket, output);
704 }
705
706
707 /**
708 * Establishes a data connection with the FTP server, returning
709 * a Socket for the connection if successful. If a restart
710 * offset has been set with {@link #setRestartOffset(long)},
711 * a REST command is issued to the server with the offset as
712 * an argument before establishing the data connection. Active
713 * mode connections also cause a local PORT command to be issued.
714 * <p>
715 * @param command The int representation of the FTP command to send.
716 * @param arg The arguments to the FTP command. If this parameter is
717 * set to null, then the command is sent with no argument.
718 * @return A Socket corresponding to the established data connection.
719 * Null is returned if an FTP protocol error is reported at
720 * any point during the establishment and initialization of
721 * the connection.
722 * @exception IOException If an I/O error occurs while either sending a
723 * command to the server or receiving a reply from the server.
724 * @deprecated (3.3) Use {@link #_openDataConnection_(FTPCmd, String)} instead
725 */
726 @Deprecated
727 protected Socket _openDataConnection_(int command, String arg)
728 throws IOException
729 {
730 return _openDataConnection_(FTPCommand.getCommand(command), arg);
731 }
732
733 /**
734 * Establishes a data connection with the FTP server, returning
735 * a Socket for the connection if successful. If a restart
736 * offset has been set with {@link #setRestartOffset(long)},
737 * a REST command is issued to the server with the offset as
738 * an argument before establishing the data connection. Active
739 * mode connections also cause a local PORT command to be issued.
740 * <p>
741 * @param command The int representation of the FTP command to send.
742 * @param arg The arguments to the FTP command. If this parameter is
743 * set to null, then the command is sent with no argument.
744 * @return A Socket corresponding to the established data connection.
745 * Null is returned if an FTP protocol error is reported at
746 * any point during the establishment and initialization of
747 * the connection.
748 * @exception IOException If an I/O error occurs while either sending a
749 * command to the server or receiving a reply from the server.
750 * @since 3.3
751 */
752 protected Socket _openDataConnection_(FTPCmd command, String arg)
753 throws IOException
754 {
755 return _openDataConnection_(command.getCommand(), arg);
756 }
757
758 /**
759 * Establishes a data connection with the FTP server, returning
760 * a Socket for the connection if successful. If a restart
761 * offset has been set with {@link #setRestartOffset(long)},
762 * a REST command is issued to the server with the offset as
763 * an argument before establishing the data connection. Active
764 * mode connections also cause a local PORT command to be issued.
765 * <p>
766 * @param command The text representation of the FTP command to send.
767 * @param arg The arguments to the FTP command. If this parameter is
768 * set to null, then the command is sent with no argument.
769 * @return A Socket corresponding to the established data connection.
770 * Null is returned if an FTP protocol error is reported at
771 * any point during the establishment and initialization of
772 * the connection.
773 * @exception IOException If an I/O error occurs while either sending a
774 * command to the server or receiving a reply from the server.
775 * @since 3.1
776 */
777 protected Socket _openDataConnection_(String command, String arg)
778 throws IOException
779 {
780 if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE &&
781 __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
782 return null;
783 }
784
785 final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address;
786
787 Socket socket;
788
789 if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE)
790 {
791 // if no activePortRange was set (correctly) -> getActivePort() = 0
792 // -> new ServerSocket(0) -> bind to any free local port
793 ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress());
794
795 try {
796 // Try EPRT only if remote server is over IPv6, if not use PORT,
797 // because EPRT has no advantage over PORT on IPv4.
798 // It could even have the disadvantage,
799 // that EPRT will make the data connection fail, because
800 // today's intelligent NAT Firewalls are able to
801 // substitute IP addresses in the PORT command,
802 // but might not be able to recognize the EPRT command.
803 if (isInet6Address) {
804 if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) {
805 return null;
806 }
807 } else {
808 if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) {
809 return null;
810 }
811 }
812
813 if ((__restartOffset > 0) && !restart(__restartOffset)) {
814 return null;
815 }
816
817 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
818 return null;
819 }
820
821 // For now, let's just use the data timeout value for waiting for
822 // the data connection. It may be desirable to let this be a
823 // separately configurable value. In any case, we really want
824 // to allow preventing the accept from blocking indefinitely.
825 if (__dataTimeout >= 0) {
826 server.setSoTimeout(__dataTimeout);
827 }
828 socket = server.accept();
829
830 // Ensure the timeout is set before any commands are issued on the new socket
831 if (__dataTimeout >= 0) {
832 socket.setSoTimeout(__dataTimeout);
833 }
834 if (__receiveDataSocketBufferSize > 0) {
835 socket.setReceiveBufferSize(__receiveDataSocketBufferSize);
836 }
837 if (__sendDataSocketBufferSize > 0) {
838 socket.setSendBufferSize(__sendDataSocketBufferSize);
839 }
840 } finally {
841 server.close();
842 }
843 }
844 else
845 { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
846
847 // Try EPSV command first on IPv6 - and IPv4 if enabled.
848 // When using IPv4 with NAT it has the advantage
849 // to work with more rare configurations.
850 // E.g. if FTP server has a static PASV address (external network)
851 // and the client is coming from another internal network.
852 // In that case the data connection after PASV command would fail,
853 // while EPSV would make the client succeed by taking just the port.
854 boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
855 if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE)
856 {
857 _parseExtendedPassiveModeReply(_replyLines.get(0));
858 }
859 else
860 {
861 if (isInet6Address) {
862 return null; // Must use EPSV for IPV6
863 }
864 // If EPSV failed on IPV4, revert to PASV
865 if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
866 return null;
867 }
868 _parsePassiveModeReply(_replyLines.get(0));
869 }
870
871 socket = _socketFactory_.createSocket();
872 if (__receiveDataSocketBufferSize > 0) {
873 socket.setReceiveBufferSize(__receiveDataSocketBufferSize);
874 }
875 if (__sendDataSocketBufferSize > 0) {
876 socket.setSendBufferSize(__sendDataSocketBufferSize);
877 }
878 if (__passiveLocalHost != null) {
879 socket.bind(new InetSocketAddress(__passiveLocalHost, 0));
880 }
881
882 // For now, let's just use the data timeout value for waiting for
883 // the data connection. It may be desirable to let this be a
884 // separately configurable value. In any case, we really want
885 // to allow preventing the accept from blocking indefinitely.
886 if (__dataTimeout >= 0) {
887 socket.setSoTimeout(__dataTimeout);
888 }
889
890 socket.connect(new InetSocketAddress(__passiveHost, __passivePort), connectTimeout);
891 if ((__restartOffset > 0) && !restart(__restartOffset))
892 {
893 socket.close();
894 return null;
895 }
896
897 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg)))
898 {
899 socket.close();
900 return null;
901 }
902 }
903
904 if (__remoteVerificationEnabled && !verifyRemote(socket))
905 {
906 socket.close();
907
908 throw new IOException(
909 "Host attempting data connection " + socket.getInetAddress().getHostAddress() +
910 " is not same as server " + getRemoteAddress().getHostAddress());
911 }
912
913 return socket;
914 }
915
916
917 @Override
918 protected void _connectAction_() throws IOException
919 {
920 super._connectAction_(); // sets up _input_ and _output_
921 __initDefaults();
922 // must be after super._connectAction_(), because otherwise we get an
923 // Exception claiming we're not connected
924 if ( __autodetectEncoding )
925 {
926 ArrayList<String> oldReplyLines = new ArrayList<String> (_replyLines);
927 int oldReplyCode = _replyCode;
928 if ( hasFeature("UTF8") || hasFeature("UTF-8")) // UTF8 appears to be the default
929 {
930 setControlEncoding("UTF-8");
931 _controlInput_ =
932 new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
933 _controlOutput_ =
934 new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
935 }
936 // restore the original reply (server greeting)
937 _replyLines.clear();
938 _replyLines.addAll(oldReplyLines);
939 _replyCode = oldReplyCode;
940 }
941 }
942
943
944 /**
945 * Sets the timeout in milliseconds to use when reading from the
946 * data connection. This timeout will be set immediately after
947 * opening the data connection, provided that the value is ≥ 0.
948 * <p>
949 * <b>Note:</b> the timeout will also be applied when calling accept()
950 * whilst establishing an active local data connection.
951 * @param timeout The default timeout in milliseconds that is used when
952 * opening a data connection socket. The value 0 means an infinite timeout.
953 */
954 public void setDataTimeout(int timeout)
955 {
956 __dataTimeout = timeout;
957 }
958
959 /**
960 * set the factory used for parser creation to the supplied factory object.
961 *
962 * @param parserFactory
963 * factory object used to create FTPFileEntryParsers
964 *
965 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
966 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
967 */
968 public void setParserFactory(FTPFileEntryParserFactory parserFactory) {
969 __parserFactory = parserFactory;
970 }
971
972
973 /**
974 * Closes the connection to the FTP server and restores
975 * connection parameters to the default values.
976 * <p>
977 * @exception IOException If an error occurs while disconnecting.
978 */
979 @Override
980 public void disconnect() throws IOException
981 {
982 super.disconnect();
983 __initDefaults();
984 }
985
986
987 /**
988 * Enable or disable verification that the remote host taking part
989 * of a data connection is the same as the host to which the control
990 * connection is attached. The default is for verification to be
991 * enabled. You may set this value at any time, whether the
992 * FTPClient is currently connected or not.
993 * <p>
994 * @param enable True to enable verification, false to disable verification.
995 */
996 public void setRemoteVerificationEnabled(boolean enable)
997 {
998 __remoteVerificationEnabled = enable;
999 }
1000
1001 /**
1002 * Return whether or not verification of the remote host participating
1003 * in data connections is enabled. The default behavior is for
1004 * verification to be enabled.
1005 * <p>
1006 * @return True if verification is enabled, false if not.
1007 */
1008 public boolean isRemoteVerificationEnabled()
1009 {
1010 return __remoteVerificationEnabled;
1011 }
1012
1013 /**
1014 * Login to the FTP server using the provided username and password.
1015 * <p>
1016 * @param username The username to login under.
1017 * @param password The password to use.
1018 * @return True if successfully completed, false if not.
1019 * @exception FTPConnectionClosedException
1020 * If the FTP server prematurely closes the connection as a result
1021 * of the client being idle or some other reason causing the server
1022 * to send FTP reply code 421. This exception may be caught either
1023 * as an IOException or independently as itself.
1024 * @exception IOException If an I/O error occurs while either sending a
1025 * command to the server or receiving a reply from the server.
1026 */
1027 public boolean login(String username, String password) throws IOException
1028 {
1029
1030 user(username);
1031
1032 if (FTPReply.isPositiveCompletion(_replyCode)) {
1033 return true;
1034 }
1035
1036 // If we get here, we either have an error code, or an intermmediate
1037 // reply requesting password.
1038 if (!FTPReply.isPositiveIntermediate(_replyCode)) {
1039 return false;
1040 }
1041
1042 return FTPReply.isPositiveCompletion(pass(password));
1043 }
1044
1045
1046 /**
1047 * Login to the FTP server using the provided username, password,
1048 * and account. If no account is required by the server, only
1049 * the username and password, the account information is not used.
1050 * <p>
1051 * @param username The username to login under.
1052 * @param password The password to use.
1053 * @param account The account to use.
1054 * @return True if successfully completed, false if not.
1055 * @exception FTPConnectionClosedException
1056 * If the FTP server prematurely closes the connection as a result
1057 * of the client being idle or some other reason causing the server
1058 * to send FTP reply code 421. This exception may be caught either
1059 * as an IOException or independently as itself.
1060 * @exception IOException If an I/O error occurs while either sending a
1061 * command to the server or receiving a reply from the server.
1062 */
1063 public boolean login(String username, String password, String account)
1064 throws IOException
1065 {
1066 user(username);
1067
1068 if (FTPReply.isPositiveCompletion(_replyCode)) {
1069 return true;
1070 }
1071
1072 // If we get here, we either have an error code, or an intermmediate
1073 // reply requesting password.
1074 if (!FTPReply.isPositiveIntermediate(_replyCode)) {
1075 return false;
1076 }
1077
1078 pass(password);
1079
1080 if (FTPReply.isPositiveCompletion(_replyCode)) {
1081 return true;
1082 }
1083
1084 if (!FTPReply.isPositiveIntermediate(_replyCode)) {
1085 return false;
1086 }
1087
1088 return FTPReply.isPositiveCompletion(acct(account));
1089 }
1090
1091 /**
1092 * Logout of the FTP server by sending the QUIT command.
1093 * <p>
1094 * @return True if successfully completed, false if not.
1095 * @exception FTPConnectionClosedException
1096 * If the FTP server prematurely closes the connection as a result
1097 * of the client being idle or some other reason causing the server
1098 * to send FTP reply code 421. This exception may be caught either
1099 * as an IOException or independently as itself.
1100 * @exception IOException If an I/O error occurs while either sending a
1101 * command to the server or receiving a reply from the server.
1102 */
1103 public boolean logout() throws IOException
1104 {
1105 return FTPReply.isPositiveCompletion(quit());
1106 }
1107
1108
1109 /**
1110 * Change the current working directory of the FTP session.
1111 * <p>
1112 * @param pathname The new current working directory.
1113 * @return True if successfully completed, false if not.
1114 * @exception FTPConnectionClosedException
1115 * If the FTP server prematurely closes the connection as a result
1116 * of the client being idle or some other reason causing the server
1117 * to send FTP reply code 421. This exception may be caught either
1118 * as an IOException or independently as itself.
1119 * @exception IOException If an I/O error occurs while either sending a
1120 * command to the server or receiving a reply from the server.
1121 */
1122 public boolean changeWorkingDirectory(String pathname) throws IOException
1123 {
1124 return FTPReply.isPositiveCompletion(cwd(pathname));
1125 }
1126
1127
1128 /**
1129 * Change to the parent directory of the current working directory.
1130 * <p>
1131 * @return True if successfully completed, false if not.
1132 * @exception FTPConnectionClosedException
1133 * If the FTP server prematurely closes the connection as a result
1134 * of the client being idle or some other reason causing the server
1135 * to send FTP reply code 421. This exception may be caught either
1136 * as an IOException or independently as itself.
1137 * @exception IOException If an I/O error occurs while either sending a
1138 * command to the server or receiving a reply from the server.
1139 */
1140 public boolean changeToParentDirectory() throws IOException
1141 {
1142 return FTPReply.isPositiveCompletion(cdup());
1143 }
1144
1145
1146 /**
1147 * Issue the FTP SMNT command.
1148 * <p>
1149 * @param pathname The pathname to mount.
1150 * @return True if successfully completed, false if not.
1151 * @exception FTPConnectionClosedException
1152 * If the FTP server prematurely closes the connection as a result
1153 * of the client being idle or some other reason causing the server
1154 * to send FTP reply code 421. This exception may be caught either
1155 * as an IOException or independently as itself.
1156 * @exception IOException If an I/O error occurs while either sending a
1157 * command to the server or receiving a reply from the server.
1158 */
1159 public boolean structureMount(String pathname) throws IOException
1160 {
1161 return FTPReply.isPositiveCompletion(smnt(pathname));
1162 }
1163
1164 /**
1165 * Reinitialize the FTP session. Not all FTP servers support this
1166 * command, which issues the FTP REIN command.
1167 * <p>
1168 * @return True if successfully completed, false if not.
1169 * @exception FTPConnectionClosedException
1170 * If the FTP server prematurely closes the connection as a result
1171 * of the client being idle or some other reason causing the server
1172 * to send FTP reply code 421. This exception may be caught either
1173 * as an IOException or independently as itself.
1174 * @exception IOException If an I/O error occurs while either sending a
1175 * command to the server or receiving a reply from the server.
1176 */
1177 boolean reinitialize() throws IOException
1178 {
1179 rein();
1180
1181 if (FTPReply.isPositiveCompletion(_replyCode) ||
1182 (FTPReply.isPositivePreliminary(_replyCode) &&
1183 FTPReply.isPositiveCompletion(getReply())))
1184 {
1185
1186 __initDefaults();
1187
1188 return true;
1189 }
1190
1191 return false;
1192 }
1193
1194
1195 /**
1196 * Set the current data connection mode to
1197 * <code>ACTIVE_LOCAL_DATA_CONNECTION_MODE</code>. No communication
1198 * with the FTP server is conducted, but this causes all future data
1199 * transfers to require the FTP server to connect to the client's
1200 * data port. Additionally, to accommodate differences between socket
1201 * implementations on different platforms, this method causes the
1202 * client to issue a PORT command before every data transfer.
1203 */
1204 public void enterLocalActiveMode()
1205 {
1206 __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
1207 __passiveHost = null;
1208 __passivePort = -1;
1209 }
1210
1211
1212 /**
1213 * Set the current data connection mode to
1214 * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code>. Use this
1215 * method only for data transfers between the client and server.
1216 * This method causes a PASV (or EPSV) command to be issued to the server
1217 * before the opening of every data connection, telling the server to
1218 * open a data port to which the client will connect to conduct
1219 * data transfers. The FTPClient will stay in
1220 * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code> until the
1221 * mode is changed by calling some other method such as
1222 * {@link #enterLocalActiveMode enterLocalActiveMode() }
1223 * <p>
1224 * <b>N.B.</b> currently calling any connect method will reset the mode to
1225 * ACTIVE_LOCAL_DATA_CONNECTION_MODE.
1226 */
1227 public void enterLocalPassiveMode()
1228 {
1229 __dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE;
1230 // These will be set when just before a data connection is opened
1231 // in _openDataConnection_()
1232 __passiveHost = null;
1233 __passivePort = -1;
1234 }
1235
1236
1237 /**
1238 * Set the current data connection mode to
1239 * <code> ACTIVE_REMOTE_DATA_CONNECTION </code>. Use this method only
1240 * for server to server data transfers. This method issues a PORT
1241 * command to the server, indicating the other server and port to which
1242 * it should connect for data transfers. You must call this method
1243 * before EVERY server to server transfer attempt. The FTPClient will
1244 * NOT automatically continue to issue PORT commands. You also
1245 * must remember to call
1246 * {@link #enterLocalActiveMode enterLocalActiveMode() } if you
1247 * wish to return to the normal data connection mode.
1248 * <p>
1249 * @param host The passive mode server accepting connections for data
1250 * transfers.
1251 * @param port The passive mode server's data port.
1252 * @return True if successfully completed, false if not.
1253 * @exception FTPConnectionClosedException
1254 * If the FTP server prematurely closes the connection as a result
1255 * of the client being idle or some other reason causing the server
1256 * to send FTP reply code 421. This exception may be caught either
1257 * as an IOException or independently as itself.
1258 * @exception IOException If an I/O error occurs while either sending a
1259 * command to the server or receiving a reply from the server.
1260 */
1261 public boolean enterRemoteActiveMode(InetAddress host, int port)
1262 throws IOException
1263 {
1264 if (FTPReply.isPositiveCompletion(port(host, port)))
1265 {
1266 __dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE;
1267 __passiveHost = null;
1268 __passivePort = -1;
1269 return true;
1270 }
1271 return false;
1272 }
1273
1274 /**
1275 * Set the current data connection mode to
1276 * <code> PASSIVE_REMOTE_DATA_CONNECTION_MODE </code>. Use this
1277 * method only for server to server data transfers.
1278 * This method issues a PASV command to the server, telling it to
1279 * open a data port to which the active server will connect to conduct
1280 * data transfers. You must call this method
1281 * before EVERY server to server transfer attempt. The FTPClient will
1282 * NOT automatically continue to issue PASV commands. You also
1283 * must remember to call
1284 * {@link #enterLocalActiveMode enterLocalActiveMode() } if you
1285 * wish to return to the normal data connection mode.
1286 * <p>
1287 * @return True if successfully completed, false if not.
1288 * @exception FTPConnectionClosedException
1289 * If the FTP server prematurely closes the connection as a result
1290 * of the client being idle or some other reason causing the server
1291 * to send FTP reply code 421. This exception may be caught either
1292 * as an IOException or independently as itself.
1293 * @exception IOException If an I/O error occurs while either sending a
1294 * command to the server or receiving a reply from the server.
1295 */
1296 public boolean enterRemotePassiveMode() throws IOException
1297 {
1298 if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
1299 return false;
1300 }
1301
1302 __dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE;
1303 _parsePassiveModeReply(_replyLines.get(0));
1304
1305 return true;
1306 }
1307
1308 /**
1309 * Returns the hostname or IP address (in the form of a string) returned
1310 * by the server when entering passive mode. If not in passive mode,
1311 * returns null. This method only returns a valid value AFTER a
1312 * data connection has been opened after a call to
1313 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1314 * This is because FTPClient sends a PASV command to the server only
1315 * just before opening a data connection, and not when you call
1316 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1317 * <p>
1318 * @return The passive host name if in passive mode, otherwise null.
1319 */
1320 public String getPassiveHost()
1321 {
1322 return __passiveHost;
1323 }
1324
1325 /**
1326 * If in passive mode, returns the data port of the passive host.
1327 * This method only returns a valid value AFTER a
1328 * data connection has been opened after a call to
1329 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1330 * This is because FTPClient sends a PASV command to the server only
1331 * just before opening a data connection, and not when you call
1332 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1333 * <p>
1334 * @return The data port of the passive server. If not in passive
1335 * mode, undefined.
1336 */
1337 public int getPassivePort()
1338 {
1339 return __passivePort;
1340 }
1341
1342
1343 /**
1344 * Returns the current data connection mode (one of the
1345 * <code> _DATA_CONNECTION_MODE </code> constants.
1346 * <p>
1347 * @return The current data connection mode (one of the
1348 * <code> _DATA_CONNECTION_MODE </code> constants.
1349 */
1350 public int getDataConnectionMode()
1351 {
1352 return __dataConnectionMode;
1353 }
1354
1355 /**
1356 * Get the client port for active mode.
1357 * <p>
1358 * @return The client port for active mode.
1359 */
1360 private int getActivePort()
1361 {
1362 if (__activeMinPort > 0 && __activeMaxPort >= __activeMinPort)
1363 {
1364 if (__activeMaxPort == __activeMinPort) {
1365 return __activeMaxPort;
1366 }
1367 // Get a random port between the min and max port range
1368 return __random.nextInt(__activeMaxPort - __activeMinPort + 1) + __activeMinPort;
1369 }
1370 else
1371 {
1372 // default port
1373 return 0;
1374 }
1375 }
1376
1377 /**
1378 * Get the host address for active mode; allows the local address to be overridden.
1379 * <p>
1380 * @return __activeExternalHost if non-null, else getLocalAddress()
1381 * @see #setActiveExternalIPAddress(String)
1382 */
1383 private InetAddress getHostAddress()
1384 {
1385 if (__activeExternalHost != null)
1386 {
1387 return __activeExternalHost;
1388 }
1389 else
1390 {
1391 // default local address
1392 return getLocalAddress();
1393 }
1394 }
1395
1396 /**
1397 * Get the reported host address for active mode EPRT/PORT commands;
1398 * allows override of {@link #getHostAddress()}.
1399 *
1400 * Useful for FTP Client behind Firewall NAT.
1401 * <p>
1402 * @return __reportActiveExternalHost if non-null, else getHostAddress();
1403 */
1404 private InetAddress getReportHostAddress() {
1405 if (__reportActiveExternalHost != null) {
1406 return __reportActiveExternalHost ;
1407 } else {
1408 return getHostAddress();
1409 }
1410 }
1411
1412 /**
1413 * Set the client side port range in active mode.
1414 * <p>
1415 * @param minPort The lowest available port (inclusive).
1416 * @param maxPort The highest available port (inclusive).
1417 * @since 2.2
1418 */
1419 public void setActivePortRange(int minPort, int maxPort)
1420 {
1421 this.__activeMinPort = minPort;
1422 this.__activeMaxPort = maxPort;
1423 }
1424
1425 /**
1426 * Set the external IP address in active mode.
1427 * Useful when there are multiple network cards.
1428 * <p>
1429 * @param ipAddress The external IP address of this machine.
1430 * @throws UnknownHostException if the ipAddress cannot be resolved
1431 * @since 2.2
1432 */
1433 public void setActiveExternalIPAddress(String ipAddress) throws UnknownHostException
1434 {
1435 this.__activeExternalHost = InetAddress.getByName(ipAddress);
1436 }
1437
1438 /**
1439 * Set the local IP address to use in passive mode.
1440 * Useful when there are multiple network cards.
1441 * <p>
1442 * @param ipAddress The local IP address of this machine.
1443 * @throws UnknownHostException if the ipAddress cannot be resolved
1444 */
1445 public void setPassiveLocalIPAddress(String ipAddress) throws UnknownHostException
1446 {
1447 this.__passiveLocalHost = InetAddress.getByName(ipAddress);
1448 }
1449
1450 /**
1451 * Set the local IP address to use in passive mode.
1452 * Useful when there are multiple network cards.
1453 * <p>
1454 * @param inetAddress The local IP address of this machine.
1455 */
1456 public void setPassiveLocalIPAddress(InetAddress inetAddress)
1457 {
1458 this.__passiveLocalHost = inetAddress;
1459 }
1460
1461 /**
1462 * Set the local IP address in passive mode.
1463 * Useful when there are multiple network cards.
1464 * <p>
1465 * @return The local IP address in passive mode.
1466 */
1467 public InetAddress getPassiveLocalIPAddress()
1468 {
1469 return this.__passiveLocalHost;
1470 }
1471
1472 /**
1473 * Set the external IP address to report in EPRT/PORT commands in active mode.
1474 * Useful when there are multiple network cards.
1475 * <p>
1476 * @param ipAddress The external IP address of this machine.
1477 * @throws UnknownHostException if the ipAddress cannot be resolved
1478 * @since 3.1
1479 * @see #getReportHostAddress()
1480 */
1481 public void setReportActiveExternalIPAddress(String ipAddress) throws UnknownHostException
1482 {
1483 this.__reportActiveExternalHost = InetAddress.getByName(ipAddress);
1484 }
1485
1486
1487 /**
1488 * Sets the file type to be transferred. This should be one of
1489 * <code> FTP.ASCII_FILE_TYPE </code>, <code> FTP.BINARY_FILE_TYPE</code>,
1490 * etc. The file type only needs to be set when you want to change the
1491 * type. After changing it, the new type stays in effect until you change
1492 * it again. The default file type is <code> FTP.ASCII_FILE_TYPE </code>
1493 * if this method is never called.
1494 * <br>
1495 * The server default is supposed to be ASCII (see RFC 959), however many
1496 * ftp servers default to BINARY. <b>To ensure correct operation with all servers,
1497 * always specify the appropriate file type after connecting to the server.</b>
1498 * <br>
1499 * <p>
1500 * <b>N.B.</b> currently calling any connect method will reset the type to
1501 * FTP.ASCII_FILE_TYPE.
1502 * @param fileType The <code> _FILE_TYPE </code> constant indcating the
1503 * type of file.
1504 * @return True if successfully completed, false if not.
1505 * @exception FTPConnectionClosedException
1506 * If the FTP server prematurely closes the connection as a result
1507 * of the client being idle or some other reason causing the server
1508 * to send FTP reply code 421. This exception may be caught either
1509 * as an IOException or independently as itself.
1510 * @exception IOException If an I/O error occurs while either sending a
1511 * command to the server or receiving a reply from the server.
1512 */
1513 public boolean setFileType(int fileType) throws IOException
1514 {
1515 if (FTPReply.isPositiveCompletion(type(fileType)))
1516 {
1517 __fileType = fileType;
1518 __fileFormat = FTP.NON_PRINT_TEXT_FORMAT;
1519 return true;
1520 }
1521 return false;
1522 }
1523
1524
1525 /**
1526 * Sets the file type to be transferred and the format. The type should be
1527 * one of <code> FTP.ASCII_FILE_TYPE </code>,
1528 * <code> FTP.BINARY_FILE_TYPE </code>, etc. The file type only needs to
1529 * be set when you want to change the type. After changing it, the new
1530 * type stays in effect until you change it again. The default file type
1531 * is <code> FTP.ASCII_FILE_TYPE </code> if this method is never called.
1532 * <br>
1533 * The server default is supposed to be ASCII (see RFC 959), however many
1534 * ftp servers default to BINARY. <b>To ensure correct operation with all servers,
1535 * always specify the appropriate file type after connecting to the server.</b>
1536 * <br>
1537 * The format should be one of the FTP class <code> TEXT_FORMAT </code>
1538 * constants, or if the type is <code> FTP.LOCAL_FILE_TYPE </code>, the
1539 * format should be the byte size for that type. The default format
1540 * is <code> FTP.NON_PRINT_TEXT_FORMAT </code> if this method is never
1541 * called.
1542 * <p>
1543 * <b>N.B.</b> currently calling any connect method will reset the type to
1544 * FTP.ASCII_FILE_TYPE and the formatOrByteSize to FTP.NON_PRINT_TEXT_FORMAT.
1545 * <p>
1546 * @param fileType The <code> _FILE_TYPE </code> constant indcating the
1547 * type of file.
1548 * @param formatOrByteSize The format of the file (one of the
1549 * <code>_FORMAT</code> constants. In the case of
1550 * <code>LOCAL_FILE_TYPE</code>, the byte size.
1551 * <p>
1552 * @return True if successfully completed, false if not.
1553 * @exception FTPConnectionClosedException
1554 * If the FTP server prematurely closes the connection as a result
1555 * of the client being idle or some other reason causing the server
1556 * to send FTP reply code 421. This exception may be caught either
1557 * as an IOException or independently as itself.
1558 * @exception IOException If an I/O error occurs while either sending a
1559 * command to the server or receiving a reply from the server.
1560 */
1561 public boolean setFileType(int fileType, int formatOrByteSize)
1562 throws IOException
1563 {
1564 if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize)))
1565 {
1566 __fileType = fileType;
1567 __fileFormat = formatOrByteSize;
1568 return true;
1569 }
1570 return false;
1571 }
1572
1573
1574 /**
1575 * Sets the file structure. The default structure is
1576 * <code> FTP.FILE_STRUCTURE </code> if this method is never called
1577 * or if a connect method is called.
1578 * <p>
1579 * @param structure The structure of the file (one of the FTP class
1580 * <code>_STRUCTURE</code> constants).
1581 * @return True if successfully completed, false if not.
1582 * @exception FTPConnectionClosedException
1583 * If the FTP server prematurely closes the connection as a result
1584 * of the client being idle or some other reason causing the server
1585 * to send FTP reply code 421. This exception may be caught either
1586 * as an IOException or independently as itself.
1587 * @exception IOException If an I/O error occurs while either sending a
1588 * command to the server or receiving a reply from the server.
1589 */
1590 public boolean setFileStructure(int structure) throws IOException
1591 {
1592 if (FTPReply.isPositiveCompletion(stru(structure)))
1593 {
1594 __fileStructure = structure;
1595 return true;
1596 }
1597 return false;
1598 }
1599
1600
1601 /**
1602 * Sets the transfer mode. The default transfer mode
1603 * <code> FTP.STREAM_TRANSFER_MODE </code> if this method is never called
1604 * or if a connect method is called.
1605 * <p>
1606 * @param mode The new transfer mode to use (one of the FTP class
1607 * <code>_TRANSFER_MODE</code> constants).
1608 * @return True if successfully completed, false if not.
1609 * @exception FTPConnectionClosedException
1610 * If the FTP server prematurely closes the connection as a result
1611 * of the client being idle or some other reason causing the server
1612 * to send FTP reply code 421. This exception may be caught either
1613 * as an IOException or independently as itself.
1614 * @exception IOException If an I/O error occurs while either sending a
1615 * command to the server or receiving a reply from the server.
1616 */
1617 public boolean setFileTransferMode(int mode) throws IOException
1618 {
1619 if (FTPReply.isPositiveCompletion(mode(mode)))
1620 {
1621 __fileTransferMode = mode;
1622 return true;
1623 }
1624 return false;
1625 }
1626
1627
1628 /**
1629 * Initiate a server to server file transfer. This method tells the
1630 * server to which the client is connected to retrieve a given file from
1631 * the other server.
1632 * <p>
1633 * @param filename The name of the file to retrieve.
1634 * @return True if successfully completed, false if not.
1635 * @exception FTPConnectionClosedException
1636 * If the FTP server prematurely closes the connection as a result
1637 * of the client being idle or some other reason causing the server
1638 * to send FTP reply code 421. This exception may be caught either
1639 * as an IOException or independently as itself.
1640 * @exception IOException If an I/O error occurs while either sending a
1641 * command to the server or receiving a reply from the server.
1642 */
1643 public boolean remoteRetrieve(String filename) throws IOException
1644 {
1645 if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1646 __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
1647 return FTPReply.isPositivePreliminary(retr(filename));
1648 }
1649 return false;
1650 }
1651
1652
1653 /**
1654 * Initiate a server to server file transfer. This method tells the
1655 * server to which the client is connected to store a file on
1656 * the other server using the given filename. The other server must
1657 * have had a <code> remoteRetrieve </code> issued to it by another
1658 * FTPClient.
1659 * <p>
1660 * @param filename The name to call the file that is to be stored.
1661 * @return True if successfully completed, false if not.
1662 * @exception FTPConnectionClosedException
1663 * If the FTP server prematurely closes the connection as a result
1664 * of the client being idle or some other reason causing the server
1665 * to send FTP reply code 421. This exception may be caught either
1666 * as an IOException or independently as itself.
1667 * @exception IOException If an I/O error occurs while either sending a
1668 * command to the server or receiving a reply from the server.
1669 */
1670 public boolean remoteStore(String filename) throws IOException
1671 {
1672 if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1673 __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
1674 return FTPReply.isPositivePreliminary(stor(filename));
1675 }
1676 return false;
1677 }
1678
1679
1680 /**
1681 * Initiate a server to server file transfer. This method tells the
1682 * server to which the client is connected to store a file on
1683 * the other server using a unique filename based on the given filename.
1684 * The other server must have had a <code> remoteRetrieve </code> issued
1685 * to it by another FTPClient.
1686 * <p>
1687 * @param filename The name on which to base the filename of the file
1688 * that is to be stored.
1689 * @return True if successfully completed, false if not.
1690 * @exception FTPConnectionClosedException
1691 * If the FTP server prematurely closes the connection as a result
1692 * of the client being idle or some other reason causing the server
1693 * to send FTP reply code 421. This exception may be caught either
1694 * as an IOException or independently as itself.
1695 * @exception IOException If an I/O error occurs while either sending a
1696 * command to the server or receiving a reply from the server.
1697 */
1698 public boolean remoteStoreUnique(String filename) throws IOException
1699 {
1700 if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1701 __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
1702 return FTPReply.isPositivePreliminary(stou(filename));
1703 }
1704 return false;
1705 }
1706
1707
1708 /**
1709 * Initiate a server to server file transfer. This method tells the
1710 * server to which the client is connected to store a file on
1711 * the other server using a unique filename.
1712 * The other server must have had a <code> remoteRetrieve </code> issued
1713 * to it by another FTPClient. Many FTP servers require that a base
1714 * filename be given from which the unique filename can be derived. For
1715 * those servers use the other version of <code> remoteStoreUnique</code>
1716 * <p>
1717 * @return True if successfully completed, false if not.
1718 * @exception FTPConnectionClosedException
1719 * If the FTP server prematurely closes the connection as a result
1720 * of the client being idle or some other reason causing the server
1721 * to send FTP reply code 421. This exception may be caught either
1722 * as an IOException or independently as itself.
1723 * @exception IOException If an I/O error occurs while either sending a
1724 * command to the server or receiving a reply from the server.
1725 */
1726 public boolean remoteStoreUnique() throws IOException
1727 {
1728 if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1729 __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
1730 return FTPReply.isPositivePreliminary(stou());
1731 }
1732 return false;
1733 }
1734
1735 // For server to server transfers
1736 /**
1737 * Initiate a server to server file transfer. This method tells the
1738 * server to which the client is connected to append to a given file on
1739 * the other server. The other server must have had a
1740 * <code> remoteRetrieve </code> issued to it by another FTPClient.
1741 * <p>
1742 * @param filename The name of the file to be appended to, or if the
1743 * file does not exist, the name to call the file being stored.
1744 * <p>
1745 * @return True if successfully completed, false if not.
1746 * @exception FTPConnectionClosedException
1747 * If the FTP server prematurely closes the connection as a result
1748 * of the client being idle or some other reason causing the server
1749 * to send FTP reply code 421. This exception may be caught either
1750 * as an IOException or independently as itself.
1751 * @exception IOException If an I/O error occurs while either sending a
1752 * command to the server or receiving a reply from the server.
1753 */
1754 public boolean remoteAppend(String filename) throws IOException
1755 {
1756 if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1757 __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
1758 return FTPReply.isPositivePreliminary(appe(filename));
1759 }
1760 return false;
1761 }
1762
1763 /**
1764 * There are a few FTPClient methods that do not complete the
1765 * entire sequence of FTP commands to complete a transaction. These
1766 * commands require some action by the programmer after the reception
1767 * of a positive intermediate command. After the programmer's code
1768 * completes its actions, it must call this method to receive
1769 * the completion reply from the server and verify the success of the
1770 * entire transaction.
1771 * <p>
1772 * For example,
1773 * <pre>
1774 * InputStream input;
1775 * OutputStream output;
1776 * input = new FileInputStream("foobaz.txt");
1777 * output = ftp.storeFileStream("foobar.txt")
1778 * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
1779 * input.close();
1780 * output.close();
1781 * ftp.logout();
1782 * ftp.disconnect();
1783 * System.err.println("File transfer failed.");
1784 * System.exit(1);
1785 * }
1786 * Util.copyStream(input, output);
1787 * input.close();
1788 * output.close();
1789 * // Must call completePendingCommand() to finish command.
1790 * if(!ftp.completePendingCommand()) {
1791 * ftp.logout();
1792 * ftp.disconnect();
1793 * System.err.println("File transfer failed.");
1794 * System.exit(1);
1795 * }
1796 * </pre>
1797 * <p>
1798 * @return True if successfully completed, false if not.
1799 * @exception FTPConnectionClosedException
1800 * If the FTP server prematurely closes the connection as a result
1801 * of the client being idle or some other reason causing the server
1802 * to send FTP reply code 421. This exception may be caught either
1803 * as an IOException or independently as itself.
1804 * @exception IOException If an I/O error occurs while either sending a
1805 * command to the server or receiving a reply from the server.
1806 */
1807 public boolean completePendingCommand() throws IOException
1808 {
1809 return FTPReply.isPositiveCompletion(getReply());
1810 }
1811
1812
1813 /**
1814 * Retrieves a named file from the server and writes it to the given
1815 * OutputStream. This method does NOT close the given OutputStream.
1816 * If the current file type is ASCII, line separators in the file are
1817 * converted to the local representation.
1818 * <p>
1819 * Note: if you have used {@link #setRestartOffset(long)},
1820 * the file data will start from the selected offset.
1821 * @param remote The name of the remote file.
1822 * @param local The local OutputStream to which to write the file.
1823 * @return True if successfully completed, false if not.
1824 * @exception FTPConnectionClosedException
1825 * If the FTP server prematurely closes the connection as a result
1826 * of the client being idle or some other reason causing the server
1827 * to send FTP reply code 421. This exception may be caught either
1828 * as an IOException or independently as itself.
1829 * @exception org.apache.commons.net.io.CopyStreamException
1830 * If an I/O error occurs while actually
1831 * transferring the file. The CopyStreamException allows you to
1832 * determine the number of bytes transferred and the IOException
1833 * causing the error. This exception may be caught either
1834 * as an IOException or independently as itself.
1835 * @exception IOException If an I/O error occurs while either sending a
1836 * command to the server or receiving a reply from the server.
1837 */
1838 public boolean retrieveFile(String remote, OutputStream local)
1839 throws IOException
1840 {
1841 return _retrieveFile(FTPCmd.RETR.getCommand(), remote, local);
1842 }
1843
1844 /**
1845 * @since 3.1
1846 */
1847 protected boolean _retrieveFile(String command, String remote, OutputStream local)
1848 throws IOException
1849 {
1850 Socket socket = _openDataConnection_(command, remote);
1851
1852 if (socket == null) {
1853 return false;
1854 }
1855
1856 InputStream input;
1857 if (__fileType == ASCII_FILE_TYPE) {
1858 input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream()));
1859 } else {
1860 input = getBufferedInputStream(socket.getInputStream());
1861 }
1862
1863 CSL csl = null;
1864 if (__controlKeepAliveTimeout > 0) {
1865 csl = new CSL(this, __controlKeepAliveTimeout, __controlKeepAliveReplyTimeout);
1866 }
1867
1868 // Treat everything else as binary for now
1869 try
1870 {
1871 Util.copyStream(input, local, getBufferSize(),
1872 CopyStreamEvent.UNKNOWN_STREAM_SIZE, __mergeListeners(csl),
1873 false);
1874 } finally {
1875 Util.closeQuietly(socket);
1876 if (csl != null) {
1877 csl.cleanUp(); // fetch any outstanding keepalive replies
1878 }
1879 }
1880
1881 // Get the transfer response
1882 boolean ok = completePendingCommand();
1883 return ok;
1884 }
1885
1886 /**
1887 * Returns an InputStream from which a named file from the server
1888 * can be read. If the current file type is ASCII, the returned
1889 * InputStream will convert line separators in the file to
1890 * the local representation. You must close the InputStream when you
1891 * finish reading from it. The InputStream itself will take care of
1892 * closing the parent data connection socket upon being closed. To
1893 * finalize the file transfer you must call
1894 * {@link #completePendingCommand completePendingCommand } and
1895 * check its return value to verify success.
1896 * <p>
1897 * Note: if you have used {@link #setRestartOffset(long)},
1898 * the file data will start from the selected offset.
1899 *
1900 * @param remote The name of the remote file.
1901 * @return An InputStream from which the remote file can be read. If
1902 * the data connection cannot be opened (e.g., the file does not
1903 * exist), null is returned (in which case you may check the reply
1904 * code to determine the exact reason for failure).
1905 * @exception FTPConnectionClosedException
1906 * If the FTP server prematurely closes the connection as a result
1907 * of the client being idle or some other reason causing the server
1908 * to send FTP reply code 421. This exception may be caught either
1909 * as an IOException or independently as itself.
1910 * @exception IOException If an I/O error occurs while either sending a
1911 * command to the server or receiving a reply from the server.
1912 */
1913 public InputStream retrieveFileStream(String remote) throws IOException
1914 {
1915 return _retrieveFileStream(FTPCmd.RETR.getCommand(), remote);
1916 }
1917
1918 /**
1919 * @since 3.1
1920 */
1921 protected InputStream _retrieveFileStream(String command, String remote)
1922 throws IOException
1923 {
1924 Socket socket = _openDataConnection_(command, remote);
1925
1926 if (socket == null) {
1927 return null;
1928 }
1929
1930 InputStream input = socket.getInputStream();
1931 if (__fileType == ASCII_FILE_TYPE) {
1932 // We buffer ascii transfers because the buffering has to
1933 // be interposed between FromNetASCIIOutputSream and the underlying
1934 // socket input stream. We don't buffer binary transfers
1935 // because we don't want to impose a buffering policy on the
1936 // programmer if possible. Programmers can decide on their
1937 // own if they want to wrap the SocketInputStream we return
1938 // for file types other than ASCII.
1939 input = getBufferedInputStream(input);
1940 input = new FromNetASCIIInputStream(input);
1941 }
1942 return new org.apache.commons.net.io.SocketInputStream(socket, input);
1943 }
1944
1945
1946 /**
1947 * Stores a file on the server using the given name and taking input
1948 * from the given InputStream. This method does NOT close the given
1949 * InputStream. If the current file type is ASCII, line separators in
1950 * the file are transparently converted to the NETASCII format (i.e.,
1951 * you should not attempt to create a special InputStream to do this).
1952 * <p>
1953 * @param remote The name to give the remote file.
1954 * @param local The local InputStream from which to read the file.
1955 * @return True if successfully completed, false if not.
1956 * @exception FTPConnectionClosedException
1957 * If the FTP server prematurely closes the connection as a result
1958 * of the client being idle or some other reason causing the server
1959 * to send FTP reply code 421. This exception may be caught either
1960 * as an IOException or independently as itself.
1961 * @exception org.apache.commons.net.io.CopyStreamException
1962 * If an I/O error occurs while actually
1963 * transferring the file. The CopyStreamException allows you to
1964 * determine the number of bytes transferred and the IOException
1965 * causing the error. This exception may be caught either
1966 * as an IOException or independently as itself.
1967 * @exception IOException If an I/O error occurs while either sending a
1968 * command to the server or receiving a reply from the server.
1969 */
1970 public boolean storeFile(String remote, InputStream local)
1971 throws IOException
1972 {
1973 return __storeFile(FTPCmd.STOR, remote, local);
1974 }
1975
1976
1977 /**
1978 * Returns an OutputStream through which data can be written to store
1979 * a file on the server using the given name. If the current file type
1980 * is ASCII, the returned OutputStream will convert line separators in
1981 * the file to the NETASCII format (i.e., you should not attempt to
1982 * create a special OutputStream to do this). You must close the
1983 * OutputStream when you finish writing to it. The OutputStream itself
1984 * will take care of closing the parent data connection socket upon being
1985 * closed. To finalize the file transfer you must call
1986 * {@link #completePendingCommand completePendingCommand } and
1987 * check its return value to verify success.
1988 * <p>
1989 * @param remote The name to give the remote file.
1990 * @return An OutputStream through which the remote file can be written. If
1991 * the data connection cannot be opened (e.g., the file does not
1992 * exist), null is returned (in which case you may check the reply
1993 * code to determine the exact reason for failure).
1994 * @exception FTPConnectionClosedException
1995 * If the FTP server prematurely closes the connection as a result
1996 * of the client being idle or some other reason causing the server
1997 * to send FTP reply code 421. This exception may be caught either
1998 * as an IOException or independently as itself.
1999 * @exception IOException If an I/O error occurs while either sending a
2000 * command to the server or receiving a reply from the server.
2001 */
2002 public OutputStream storeFileStream(String remote) throws IOException
2003 {
2004 return __storeFileStream(FTPCmd.STOR, remote);
2005 }
2006
2007 /**
2008 * Appends to a file on the server with the given name, taking input
2009 * from the given InputStream. This method does NOT close the given
2010 * InputStream. If the current file type is ASCII, line separators in
2011 * the file are transparently converted to the NETASCII format (i.e.,
2012 * you should not attempt to create a special InputStream to do this).
2013 * <p>
2014 * @param remote The name of the remote file.
2015 * @param local The local InputStream from which to read the data to
2016 * be appended to the remote file.
2017 * @return True if successfully completed, false if not.
2018 * @exception FTPConnectionClosedException
2019 * If the FTP server prematurely closes the connection as a result
2020 * of the client being idle or some other reason causing the server
2021 * to send FTP reply code 421. This exception may be caught either
2022 * as an IOException or independently as itself.
2023 * @exception org.apache.commons.net.io.CopyStreamException
2024 * If an I/O error occurs while actually
2025 * transferring the file. The CopyStreamException allows you to
2026 * determine the number of bytes transferred and the IOException
2027 * causing the error. This exception may be caught either
2028 * as an IOException or independently as itself.
2029 * @exception IOException If an I/O error occurs while either sending a
2030 * command to the server or receiving a reply from the server.
2031 */
2032 public boolean appendFile(String remote, InputStream local)
2033 throws IOException
2034 {
2035 return __storeFile(FTPCmd.APPE, remote, local);
2036 }
2037
2038 /**
2039 * Returns an OutputStream through which data can be written to append
2040 * to a file on the server with the given name. If the current file type
2041 * is ASCII, the returned OutputStream will convert line separators in
2042 * the file to the NETASCII format (i.e., you should not attempt to
2043 * create a special OutputStream to do this). You must close the
2044 * OutputStream when you finish writing to it. The OutputStream itself
2045 * will take care of closing the parent data connection socket upon being
2046 * closed. To finalize the file transfer you must call
2047 * {@link #completePendingCommand completePendingCommand } and
2048 * check its return value to verify success.
2049 * <p>
2050 * @param remote The name of the remote file.
2051 * @return An OutputStream through which the remote file can be appended.
2052 * If the data connection cannot be opened (e.g., the file does not
2053 * exist), null is returned (in which case you may check the reply
2054 * code to determine the exact reason for failure).
2055 * @exception FTPConnectionClosedException
2056 * If the FTP server prematurely closes the connection as a result
2057 * of the client being idle or some other reason causing the server
2058 * to send FTP reply code 421. This exception may be caught either
2059 * as an IOException or independently as itself.
2060 * @exception IOException If an I/O error occurs while either sending a
2061 * command to the server or receiving a reply from the server.
2062 */
2063 public OutputStream appendFileStream(String remote) throws IOException
2064 {
2065 return __storeFileStream(FTPCmd.APPE, remote);
2066 }
2067
2068 /**
2069 * Stores a file on the server using a unique name derived from the
2070 * given name and taking input
2071 * from the given InputStream. This method does NOT close the given
2072 * InputStream. If the current file type is ASCII, line separators in
2073 * the file are transparently converted to the NETASCII format (i.e.,
2074 * you should not attempt to create a special InputStream to do this).
2075 * <p>
2076 * @param remote The name on which to base the unique name given to
2077 * the remote file.
2078 * @param local The local InputStream from which to read the file.
2079 * @return True if successfully completed, false if not.
2080 * @exception FTPConnectionClosedException
2081 * If the FTP server prematurely closes the connection as a result
2082 * of the client being idle or some other reason causing the server
2083 * to send FTP reply code 421. This exception may be caught either
2084 * as an IOException or independently as itself.
2085 * @exception org.apache.commons.net.io.CopyStreamException
2086 * If an I/O error occurs while actually
2087 * transferring the file. The CopyStreamException allows you to
2088 * determine the number of bytes transferred and the IOException
2089 * causing the error. This exception may be caught either
2090 * as an IOException or independently as itself.
2091 * @exception IOException If an I/O error occurs while either sending a
2092 * command to the server or receiving a reply from the server.
2093 */
2094 public boolean storeUniqueFile(String remote, InputStream local)
2095 throws IOException
2096 {
2097 return __storeFile(FTPCmd.STOU, remote, local);
2098 }
2099
2100
2101 /**
2102 * Returns an OutputStream through which data can be written to store
2103 * a file on the server using a unique name derived from the given name.
2104 * If the current file type
2105 * is ASCII, the returned OutputStream will convert line separators in
2106 * the file to the NETASCII format (i.e., you should not attempt to
2107 * create a special OutputStream to do this). You must close the
2108 * OutputStream when you finish writing to it. The OutputStream itself
2109 * will take care of closing the parent data connection socket upon being
2110 * closed. To finalize the file transfer you must call
2111 * {@link #completePendingCommand completePendingCommand } and
2112 * check its return value to verify success.
2113 * <p>
2114 * @param remote The name on which to base the unique name given to
2115 * the remote file.
2116 * @return An OutputStream through which the remote file can be written. If
2117 * the data connection cannot be opened (e.g., the file does not
2118 * exist), null is returned (in which case you may check the reply
2119 * code to determine the exact reason for failure).
2120 * @exception FTPConnectionClosedException
2121 * If the FTP server prematurely closes the connection as a result
2122 * of the client being idle or some other reason causing the server
2123 * to send FTP reply code 421. This exception may be caught either
2124 * as an IOException or independently as itself.
2125 * @exception IOException If an I/O error occurs while either sending a
2126 * command to the server or receiving a reply from the server.
2127 */
2128 public OutputStream storeUniqueFileStream(String remote) throws IOException
2129 {
2130 return __storeFileStream(FTPCmd.STOU, remote);
2131 }
2132
2133 /**
2134 * Stores a file on the server using a unique name assigned by the
2135 * server and taking input from the given InputStream. This method does
2136 * NOT close the given
2137 * InputStream. If the current file type is ASCII, line separators in
2138 * the file are transparently converted to the NETASCII format (i.e.,
2139 * you should not attempt to create a special InputStream to do this).
2140 * <p>
2141 * @param local The local InputStream from which to read the file.
2142 * @return True if successfully completed, false if not.
2143 * @exception FTPConnectionClosedException
2144 * If the FTP server prematurely closes the connection as a result
2145 * of the client being idle or some other reason causing the server
2146 * to send FTP reply code 421. This exception may be caught either
2147 * as an IOException or independently as itself.
2148 * @exception org.apache.commons.net.io.CopyStreamException
2149 * If an I/O error occurs while actually
2150 * transferring the file. The CopyStreamException allows you to
2151 * determine the number of bytes transferred and the IOException
2152 * causing the error. This exception may be caught either
2153 * as an IOException or independently as itself.
2154 * @exception IOException If an I/O error occurs while either sending a
2155 * command to the server or receiving a reply from the server.
2156 */
2157 public boolean storeUniqueFile(InputStream local) throws IOException
2158 {
2159 return __storeFile(FTPCmd.STOU, null, local);
2160 }
2161
2162 /**
2163 * Returns an OutputStream through which data can be written to store
2164 * a file on the server using a unique name assigned by the server.
2165 * If the current file type
2166 * is ASCII, the returned OutputStream will convert line separators in
2167 * the file to the NETASCII format (i.e., you should not attempt to
2168 * create a special OutputStream to do this). You must close the
2169 * OutputStream when you finish writing to it. The OutputStream itself
2170 * will take care of closing the parent data connection socket upon being
2171 * closed. To finalize the file transfer you must call
2172 * {@link #completePendingCommand completePendingCommand } and
2173 * check its return value to verify success.
2174 * <p>
2175 * @return An OutputStream through which the remote file can be written. If
2176 * the data connection cannot be opened (e.g., the file does not
2177 * exist), null is returned (in which case you may check the reply
2178 * code to determine the exact reason for failure).
2179 * @exception FTPConnectionClosedException
2180 * If the FTP server prematurely closes the connection as a result
2181 * of the client being idle or some other reason causing the server
2182 * to send FTP reply code 421. This exception may be caught either
2183 * as an IOException or independently as itself.
2184 * @exception IOException If an I/O error occurs while either sending a
2185 * command to the server or receiving a reply from the server.
2186 */
2187 public OutputStream storeUniqueFileStream() throws IOException
2188 {
2189 return __storeFileStream(FTPCmd.STOU, null);
2190 }
2191
2192 /**
2193 * Reserve a number of bytes on the server for the next file transfer.
2194 * <p>
2195 * @param bytes The number of bytes which the server should allocate.
2196 * @return True if successfully completed, false if not.
2197 * @exception FTPConnectionClosedException
2198 * If the FTP server prematurely closes the connection as a result
2199 * of the client being idle or some other reason causing the server
2200 * to send FTP reply code 421. This exception may be caught either
2201 * as an IOException or independently as itself.
2202 * @exception IOException If an I/O error occurs while either sending a
2203 * command to the server or receiving a reply from the server.
2204 */
2205 public boolean allocate(int bytes) throws IOException
2206 {
2207 return FTPReply.isPositiveCompletion(allo(bytes));
2208 }
2209
2210 /**
2211 * Query the server for supported features. The server may reply with a list of server-supported exensions.
2212 * For example, a typical client-server interaction might be (from RFC 2389):
2213 * <pre>
2214 C> feat
2215 S> 211-Extensions supported:
2216 S> MLST size*;create;modify*;perm;media-type
2217 S> SIZE
2218 S> COMPRESSION
2219 S> MDTM
2220 S> 211 END
2221 * </pre>
2222 * @see <a href="http://www.faqs.org/rfcs/rfc2389.html">http://www.faqs.org/rfcs/rfc2389.html</a>
2223 * @return True if successfully completed, false if not.
2224 * @throws IOException
2225 * @since 2.2
2226 */
2227 public boolean features() throws IOException {
2228 return FTPReply.isPositiveCompletion(feat());
2229 }
2230
2231 /**
2232 * Query the server for a supported feature, and returns its values (if any).
2233 * Caches the parsed response to avoid resending the command repeatedly.
2234 *
2235 * @return if the feature is present, returns the feature values (empty array if none)
2236 * Returns {@code null} if the feature is not found or the command failed.
2237 * Check {@link #getReplyCode()} or {@link #getReplyString()} if so.
2238 * @throws IOException
2239 * @since 3.0
2240 */
2241 public String[] featureValues(String feature) throws IOException {
2242 if (!initFeatureMap()) {
2243 return null;
2244 }
2245 Set<String> entries = __featuresMap.get(feature.toUpperCase(Locale.ENGLISH));
2246 if (entries != null) {
2247 return entries.toArray(new String[entries.size()]);
2248 }
2249 return null;
2250 }
2251
2252 /**
2253 * Query the server for a supported feature, and returns the its value (if any).
2254 * Caches the parsed response to avoid resending the command repeatedly.
2255 *
2256 * @return if the feature is present, returns the feature value or the empty string
2257 * if the feature exists but has no value.
2258 * Returns {@code null} if the feature is not found or the command failed.
2259 * Check {@link #getReplyCode()} or {@link #getReplyString()} if so.
2260 * @throws IOException
2261 * @since 3.0
2262 */
2263 public String featureValue(String feature) throws IOException {
2264 String [] values = featureValues(feature);
2265 if (values != null) {
2266 return values[0];
2267 }
2268 return null;
2269 }
2270
2271 /**
2272 * Query the server for a supported feature.
2273 * Caches the parsed response to avoid resending the command repeatedly.
2274 *
2275 * @param feature the name of the feature; it is converted to upper case.
2276 * @return {@code true} if the feature is present, {@code false} if the feature is not present
2277 * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
2278 * if it is necessary to distinguish these cases.
2279 *
2280 * @throws IOException
2281 * @since 3.0
2282 */
2283 public boolean hasFeature(String feature) throws IOException {
2284 if (!initFeatureMap()) {
2285 return false;
2286 }
2287 return __featuresMap.containsKey(feature.toUpperCase(Locale.ENGLISH));
2288 }
2289
2290 /**
2291 * Query the server for a supported feature with particular value,
2292 * for example "AUTH SSL" or "AUTH TLS".
2293 * Caches the parsed response to avoid resending the command repeatedly.
2294 *
2295 * @param feature the name of the feature; it is converted to upper case.
2296 * @param value the value to find.
2297 *
2298 * @return {@code true} if the feature is present, {@code false} if the feature is not present
2299 * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
2300 * if it is necessary to distinguish these cases.
2301 *
2302 * @throws IOException
2303 * @since 3.0
2304 */
2305 public boolean hasFeature(String feature, String value) throws IOException {
2306 if (!initFeatureMap()) {
2307 return false;
2308 }
2309 Set<String> entries = __featuresMap.get(feature.toUpperCase(Locale.ENGLISH));
2310 if (entries != null) {
2311 return entries.contains(value);
2312 }
2313 return false;
2314 }
2315
2316 /*
2317 * Create the feature map if not already created.
2318 */
2319 private boolean initFeatureMap() throws IOException {
2320 if (__featuresMap == null) {
2321 // Don't create map here, because next line may throw exception
2322 boolean success = FTPReply.isPositiveCompletion(feat());
2323 // we init the map here, so we don't keep trying if we know the command will fail
2324 __featuresMap = new HashMap<String, Set<String>>();
2325 if (!success) {
2326 return false;
2327 }
2328 for (String l : getReplyStrings()) {
2329 if (l.startsWith(" ")) { // it's a FEAT entry
2330 String key;
2331 String value="";
2332 int varsep = l.indexOf(' ', 1);
2333 if (varsep > 0) {
2334 key = l.substring(1, varsep);
2335 value = l.substring(varsep+1);
2336 } else {
2337 key = l.substring(1);
2338 }
2339 key = key.toUpperCase(Locale.ENGLISH);
2340 Set<String> entries = __featuresMap.get(key);
2341 if (entries == null) {
2342 entries = new HashSet<String>();
2343 __featuresMap.put(key, entries);
2344 }
2345 entries.add(value);
2346 }
2347 }
2348 }
2349 return true;
2350 }
2351
2352 /**
2353 * Reserve space on the server for the next file transfer.
2354 * <p>
2355 * @param bytes The number of bytes which the server should allocate.
2356 * @param recordSize The size of a file record.
2357 * @return True if successfully completed, false if not.
2358 * @exception FTPConnectionClosedException
2359 * If the FTP server prematurely closes the connection as a result
2360 * of the client being idle or some other reason causing the server
2361 * to send FTP reply code 421. This exception may be caught either
2362 * as an IOException or independently as itself.
2363 * @exception IOException If an I/O error occurs while either sending a
2364 * command to the server or receiving a reply from the server.
2365 */
2366 public boolean allocate(int bytes, int recordSize) throws IOException
2367 {
2368 return FTPReply.isPositiveCompletion(allo(bytes, recordSize));
2369 }
2370
2371
2372 /**
2373 * Issue a command and wait for the reply.
2374 * <p>
2375 * Should only be used with commands that return replies on the
2376 * command channel - do not use for LIST, NLST, MLSD etc.
2377 * <p>
2378 * @param command The command to invoke
2379 * @param params The parameters string, may be {@code null}
2380 * @return True if successfully completed, false if not, in which case
2381 * call {@link #getReplyCode()} or {@link #getReplyString()}
2382 * to get the reason.
2383 *
2384 * @exception IOException If an I/O error occurs while either sending a
2385 * command to the server or receiving a reply from the server.
2386 * @since 3.0
2387 */
2388 public boolean doCommand(String command, String params) throws IOException
2389 {
2390 return FTPReply.isPositiveCompletion(sendCommand(command, params));
2391 }
2392
2393 /**
2394 * Issue a command and wait for the reply, returning it as an array of strings.
2395 * <p>
2396 * Should only be used with commands that return replies on the
2397 * command channel - do not use for LIST, NLST, MLSD etc.
2398 * <p>
2399 * @param command The command to invoke
2400 * @param params The parameters string, may be {@code null}
2401 * @return The array of replies, or {@code null} if the command failed, in which case
2402 * call {@link #getReplyCode()} or {@link #getReplyString()}
2403 * to get the reason.
2404 *
2405 * @exception IOException If an I/O error occurs while either sending a
2406 * command to the server or receiving a reply from the server.
2407 * @since 3.0
2408 */
2409 public String[] doCommandAsStrings(String command, String params) throws IOException
2410 {
2411 boolean success = FTPReply.isPositiveCompletion(sendCommand(command, params));
2412 if (success){
2413 return getReplyStrings();
2414 } else {
2415 return null;
2416 }
2417 }
2418
2419 /**
2420 * Get file details using the MLST command
2421 *
2422 * @param pathname the file or directory to list, may be {@code} null
2423 * @return the file details, may be {@code null}
2424 * @throws IOException
2425 * @since 3.0
2426 */
2427 public FTPFile mlistFile(String pathname) throws IOException
2428 {
2429 boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname));
2430 if (success){
2431 String entry = getReplyStrings()[1].substring(1); // skip leading space for parser
2432 return MLSxEntryParser.parseEntry(entry);
2433 } else {
2434 return null;
2435 }
2436 }
2437
2438 /**
2439 * Generate a directory listing for the current directory using the MLSD command.
2440 *
2441 * @return the array of file entries
2442 * @throws IOException
2443 * @since 3.0
2444 */
2445 public FTPFile[] mlistDir() throws IOException
2446 {
2447 return mlistDir(null);
2448 }
2449
2450 /**
2451 * Generate a directory listing using the MLSD command.
2452 *
2453 * @param pathname the directory name, may be {@code null}
2454 * @return the array of file entries
2455 * @throws IOException
2456 * @since 3.0
2457 */
2458 public FTPFile[] mlistDir(String pathname) throws IOException
2459 {
2460 FTPListParseEngine engine = initiateMListParsing( pathname);
2461 return engine.getFiles();
2462 }
2463
2464 /**
2465 * Generate a directory listing using the MLSD command.
2466 *
2467 * @param pathname the directory name, may be {@code null}
2468 * @param filter the filter to apply to the responses
2469 * @return the array of file entries
2470 * @throws IOException
2471 * @since 3.0
2472 */
2473 public FTPFile[] mlistDir(String pathname, FTPFileFilter filter) throws IOException
2474 {
2475 FTPListParseEngine engine = initiateMListParsing( pathname);
2476 return engine.getFiles(filter);
2477 }
2478
2479 /**
2480 * Restart a <code>STREAM_TRANSFER_MODE</code> file transfer starting
2481 * from the given offset. This will only work on FTP servers supporting
2482 * the REST comand for the stream transfer mode. However, most FTP
2483 * servers support this. Any subsequent file transfer will start
2484 * reading or writing the remote file from the indicated offset.
2485 * <p>
2486 * @param offset The offset into the remote file at which to start the
2487 * next file transfer.
2488 * @return True if successfully completed, false if not.
2489 * @exception FTPConnectionClosedException
2490 * If the FTP server prematurely closes the connection as a result
2491 * of the client being idle or some other reason causing the server
2492 * to send FTP reply code 421. This exception may be caught either
2493 * as an IOException or independently as itself.
2494 * @exception IOException If an I/O error occurs while either sending a
2495 * command to the server or receiving a reply from the server.
2496 * @since 3.1 (changed from private to protected)
2497 */
2498 protected boolean restart(long offset) throws IOException
2499 {
2500 __restartOffset = 0;
2501 return FTPReply.isPositiveIntermediate(rest(Long.toString(offset)));
2502 }
2503
2504 /**
2505 * Sets the restart offset for file transfers.
2506 * <p>
2507 * The restart command is not sent to the server immediately.
2508 * It is sent when a data connection is created as part of a
2509 * subsequent command.
2510 * The restart marker is reset to zero after use.
2511 * </p>
2512 * <p>
2513 * <b>Note: This method should only be invoked immediately prior to
2514 * the transfer to which it applies.</b>
2515 *
2516 * @param offset The offset into the remote file at which to start the
2517 * next file transfer. This must be a value greater than or
2518 * equal to zero.
2519 */
2520 public void setRestartOffset(long offset)
2521 {
2522 if (offset >= 0) {
2523 __restartOffset = offset;
2524 }
2525 }
2526
2527 /**
2528 * Fetches the restart offset.
2529 * <p>
2530 * @return offset The offset into the remote file at which to start the
2531 * next file transfer.
2532 */
2533 public long getRestartOffset()
2534 {
2535 return __restartOffset;
2536 }
2537
2538
2539
2540 /**
2541 * Renames a remote file.
2542 * <p>
2543 * @param from The name of the remote file to rename.
2544 * @param to The new name of the remote file.
2545 * @return True if successfully completed, false if not.
2546 * @exception FTPConnectionClosedException
2547 * If the FTP server prematurely closes the connection as a result
2548 * of the client being idle or some other reason causing the server
2549 * to send FTP reply code 421. This exception may be caught either
2550 * as an IOException or independently as itself.
2551 * @exception IOException If an I/O error occurs while either sending a
2552 * command to the server or receiving a reply from the server.
2553 */
2554 public boolean rename(String from, String to) throws IOException
2555 {
2556 if (!FTPReply.isPositiveIntermediate(rnfr(from))) {
2557 return false;
2558 }
2559
2560 return FTPReply.isPositiveCompletion(rnto(to));
2561 }
2562
2563
2564 /**
2565 * Abort a transfer in progress.
2566 * <p>
2567 * @return True if successfully completed, false if not.
2568 * @exception FTPConnectionClosedException
2569 * If the FTP server prematurely closes the connection as a result
2570 * of the client being idle or some other reason causing the server
2571 * to send FTP reply code 421. This exception may be caught either
2572 * as an IOException or independently as itself.
2573 * @exception IOException If an I/O error occurs while either sending a
2574 * command to the server or receiving a reply from the server.
2575 */
2576 public boolean abort() throws IOException
2577 {
2578 return FTPReply.isPositiveCompletion(abor());
2579 }
2580
2581 /**
2582 * Deletes a file on the FTP server.
2583 * <p>
2584 * @param pathname The pathname of the file to be deleted.
2585 * @return True if successfully completed, false if not.
2586 * @exception FTPConnectionClosedException
2587 * If the FTP server prematurely closes the connection as a result
2588 * of the client being idle or some other reason causing the server
2589 * to send FTP reply code 421. This exception may be caught either
2590 * as an IOException or independently as itself.
2591 * @exception IOException If an I/O error occurs while either sending a
2592 * command to the server or receiving a reply from the server.
2593 */
2594 public boolean deleteFile(String pathname) throws IOException
2595 {
2596 return FTPReply.isPositiveCompletion(dele(pathname));
2597 }
2598
2599
2600 /**
2601 * Removes a directory on the FTP server (if empty).
2602 * <p>
2603 * @param pathname The pathname of the directory to remove.
2604 * @return True if successfully completed, false if not.
2605 * @exception FTPConnectionClosedException
2606 * If the FTP server prematurely closes the connection as a result
2607 * of the client being idle or some other reason causing the server
2608 * to send FTP reply code 421. This exception may be caught either
2609 * as an IOException or independently as itself.
2610 * @exception IOException If an I/O error occurs while either sending a
2611 * command to the server or receiving a reply from the server.
2612 */
2613 public boolean removeDirectory(String pathname) throws IOException
2614 {
2615 return FTPReply.isPositiveCompletion(rmd(pathname));
2616 }
2617
2618
2619 /**
2620 * Creates a new subdirectory on the FTP server in the current directory
2621 * (if a relative pathname is given) or where specified (if an absolute
2622 * pathname is given).
2623 * <p>
2624 * @param pathname The pathname of the directory to create.
2625 * @return True if successfully completed, false if not.
2626 * @exception FTPConnectionClosedException
2627 * If the FTP server prematurely closes the connection as a result
2628 * of the client being idle or some other reason causing the server
2629 * to send FTP reply code 421. This exception may be caught either
2630 * as an IOException or independently as itself.
2631 * @exception IOException If an I/O error occurs while either sending a
2632 * command to the server or receiving a reply from the server.
2633 */
2634 public boolean makeDirectory(String pathname) throws IOException
2635 {
2636 return FTPReply.isPositiveCompletion(mkd(pathname));
2637 }
2638
2639
2640 /**
2641 * Returns the pathname of the current working directory.
2642 * <p>
2643 * @return The pathname of the current working directory. If it cannot
2644 * be obtained, returns null.
2645 * @exception FTPConnectionClosedException
2646 * If the FTP server prematurely closes the connection as a result
2647 * of the client being idle or some other reason causing the server
2648 * to send FTP reply code 421. This exception may be caught either
2649 * as an IOException or independently as itself.
2650 * @exception IOException If an I/O error occurs while either sending a
2651 * command to the server or receiving a reply from the server.
2652 */
2653 public String printWorkingDirectory() throws IOException
2654 {
2655 if (pwd() != FTPReply.PATHNAME_CREATED) {
2656 return null;
2657 }
2658
2659 return __parsePathname(_replyLines.get( _replyLines.size() - 1));
2660 }
2661
2662
2663 /**
2664 * Send a site specific command.
2665 * @param arguments The site specific command and arguments.
2666 * @return True if successfully completed, false if not.
2667 * @exception FTPConnectionClosedException
2668 * If the FTP server prematurely closes the connection as a result
2669 * of the client being idle or some other reason causing the server
2670 * to send FTP reply code 421. This exception may be caught either
2671 * as an IOException or independently as itself.
2672 * @exception IOException If an I/O error occurs while either sending a
2673 * command to the server or receiving a reply from the server.
2674 */
2675 public boolean sendSiteCommand(String arguments) throws IOException
2676 {
2677 return FTPReply.isPositiveCompletion(site(arguments));
2678 }
2679
2680
2681 /**
2682 * Fetches the system type from the server and returns the string.
2683 * This value is cached for the duration of the connection after the
2684 * first call to this method. In other words, only the first time
2685 * that you invoke this method will it issue a SYST command to the
2686 * FTP server. FTPClient will remember the value and return the
2687 * cached value until a call to disconnect.
2688 * <p>
2689 * If the SYST command fails, and the system property
2690 * {@link #FTP_SYSTEM_TYPE_DEFAULT} is defined, then this is used instead.
2691 * @return The system type obtained from the server. Never null.
2692 * @exception FTPConnectionClosedException
2693 * If the FTP server prematurely closes the connection as a result
2694 * of the client being idle or some other reason causing the server
2695 * to send FTP reply code 421. This exception may be caught either
2696 * as an IOException or independently as itself.
2697 * @exception IOException If an I/O error occurs while either sending a
2698 * command to the server or receiving a reply from the server (and the default
2699 * system type property is not defined)
2700 * @since 2.2
2701 */
2702 public String getSystemType() throws IOException
2703 {
2704 //if (syst() == FTPReply.NAME_SYSTEM_TYPE)
2705 // Technically, we should expect a NAME_SYSTEM_TYPE response, but
2706 // in practice FTP servers deviate, so we soften the condition to
2707 // a positive completion.
2708 if (__systemName == null){
2709 if (FTPReply.isPositiveCompletion(syst())) {
2710 // Assume that response is not empty here (cannot be null)
2711 __systemName = _replyLines.get(_replyLines.size() - 1).substring(4);
2712 } else {
2713 // Check if the user has provided a default for when the SYST command fails
2714 String systDefault = System.getProperty(FTP_SYSTEM_TYPE_DEFAULT);
2715 if (systDefault != null) {
2716 __systemName = systDefault;
2717 } else {
2718 throw new IOException("Unable to determine system type - response: " + getReplyString());
2719 }
2720 }
2721 }
2722 return __systemName;
2723 }
2724
2725
2726 /**
2727 * Fetches the system help information from the server and returns the
2728 * full string.
2729 * <p>
2730 * @return The system help string obtained from the server. null if the
2731 * information could not be obtained.
2732 * @exception FTPConnectionClosedException
2733 * If the FTP server prematurely closes the connection as a result
2734 * of the client being idle or some other reason causing the server
2735 * to send FTP reply code 421. This exception may be caught either
2736 * as an IOException or independently as itself.
2737 * @exception IOException If an I/O error occurs while either sending a
2738 * command to the server or receiving a reply from the server.
2739 */
2740 public String listHelp() throws IOException
2741 {
2742 if (FTPReply.isPositiveCompletion(help())) {
2743 return getReplyString();
2744 }
2745 return null;
2746 }
2747
2748
2749 /**
2750 * Fetches the help information for a given command from the server and
2751 * returns the full string.
2752 * @param command The command on which to ask for help.
2753 * @return The command help string obtained from the server. null if the
2754 * information could not be obtained.
2755 * @exception FTPConnectionClosedException
2756 * If the FTP server prematurely closes the connection as a result
2757 * of the client being idle or some other reason causing the server
2758 * to send FTP reply code 421. This exception may be caught either
2759 * as an IOException or independently as itself.
2760 * @exception IOException If an I/O error occurs while either sending a
2761 * command to the server or receiving a reply from the server.
2762 */
2763 public String listHelp(String command) throws IOException
2764 {
2765 if (FTPReply.isPositiveCompletion(help(command))) {
2766 return getReplyString();
2767 }
2768 return null;
2769 }
2770
2771
2772 /**
2773 * Sends a NOOP command to the FTP server. This is useful for preventing
2774 * server timeouts.
2775 * <p>
2776 * @return True if successfully completed, false if not.
2777 * @exception FTPConnectionClosedException
2778 * If the FTP server prematurely closes the connection as a result
2779 * of the client being idle or some other reason causing the server
2780 * to send FTP reply code 421. This exception may be caught either
2781 * as an IOException or independently as itself.
2782 * @exception IOException If an I/O error occurs while either sending a
2783 * command to the server or receiving a reply from the server.
2784 */
2785 public boolean sendNoOp() throws IOException
2786 {
2787 return FTPReply.isPositiveCompletion(noop());
2788 }
2789
2790
2791 /**
2792 * Obtain a list of filenames in a directory (or just the name of a given
2793 * file, which is not particularly useful). This information is obtained
2794 * through the NLST command. If the given pathname is a directory and
2795 * contains no files, a zero length array is returned only
2796 * if the FTP server returned a positive completion code, otherwise
2797 * null is returned (the FTP server returned a 550 error No files found.).
2798 * If the directory is not empty, an array of filenames in the directory is
2799 * returned. If the pathname corresponds
2800 * to a file, only that file will be listed. The server may or may not
2801 * expand glob expressions.
2802 * <p>
2803 * @param pathname The file or directory to list.
2804 * Warning: the server may treat a leading '-' as an
2805 * option introducer. If so, try using an absolute path,
2806 * or prefix the path with ./ (unix style servers).
2807 * Some servers may support "--" as meaning end of options,
2808 * in which case "-- -xyz" should work.
2809 * @return The list of filenames contained in the given path. null if
2810 * the list could not be obtained. If there are no filenames in
2811 * the directory, a zero-length array is returned.
2812 * @exception FTPConnectionClosedException
2813 * If the FTP server prematurely closes the connection as a result
2814 * of the client being idle or some other reason causing the server
2815 * to send FTP reply code 421. This exception may be caught either
2816 * as an IOException or independently as itself.
2817 * @exception IOException If an I/O error occurs while either sending a
2818 * command to the server or receiving a reply from the server.
2819 */
2820 public String[] listNames(String pathname) throws IOException
2821 {
2822 Socket socket = _openDataConnection_(FTPCmd.NLST, getListArguments(pathname));
2823
2824 if (socket == null) {
2825 return null;
2826 }
2827
2828 BufferedReader reader =
2829 new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
2830
2831 ArrayList<String> results = new ArrayList<String>();
2832 String line;
2833 while ((line = reader.readLine()) != null) {
2834 results.add(line);
2835 }
2836
2837 reader.close();
2838 socket.close();
2839
2840 if (completePendingCommand())
2841 {
2842 String[] names = new String[ results.size() ];
2843 return results.toArray(names);
2844 }
2845
2846 return null;
2847 }
2848
2849
2850 /**
2851 * Obtain a list of filenames in the current working directory
2852 * This information is obtained through the NLST command. If the current
2853 * directory contains no files, a zero length array is returned only
2854 * if the FTP server returned a positive completion code, otherwise,
2855 * null is returned (the FTP server returned a 550 error No files found.).
2856 * If the directory is not empty, an array of filenames in the directory is
2857 * returned.
2858 * <p>
2859 * @return The list of filenames contained in the current working
2860 * directory. null if the list could not be obtained.
2861 * If there are no filenames in the directory, a zero-length array
2862 * is returned.
2863 * @exception FTPConnectionClosedException
2864 * If the FTP server prematurely closes the connection as a result
2865 * of the client being idle or some other reason causing the server
2866 * to send FTP reply code 421. This exception may be caught either
2867 * as an IOException or independently as itself.
2868 * @exception IOException If an I/O error occurs while either sending a
2869 * command to the server or receiving a reply from the server.
2870 */
2871 public String[] listNames() throws IOException
2872 {
2873 return listNames(null);
2874 }
2875
2876
2877
2878 /**
2879 * Using the default system autodetect mechanism, obtain a
2880 * list of file information for the current working directory
2881 * or for just a single file.
2882 * <p>
2883 * This information is obtained through the LIST command. The contents of
2884 * the returned array is determined by the<code> FTPFileEntryParser </code>
2885 * used.
2886 * <p>
2887 * @param pathname The file or directory to list. Since the server may
2888 * or may not expand glob expressions, using them here
2889 * is not recommended and may well cause this method to
2890 * fail.
2891 * Also, some servers treat a leading '-' as being an option.
2892 * To avoid this interpretation, use an absolute pathname
2893 * or prefix the pathname with ./ (unix style servers).
2894 * Some servers may support "--" as meaning end of options,
2895 * in which case "-- -xyz" should work.
2896 *
2897 * @return The list of file information contained in the given path in
2898 * the format determined by the autodetection mechanism
2899 * @exception FTPConnectionClosedException
2900 * If the FTP server prematurely closes the connection
2901 * as a result of the client being idle or some other
2902 * reason causing the server to send FTP reply code 421.
2903 * This exception may be caught either as an IOException
2904 * or independently as itself.
2905 * @exception IOException
2906 * If an I/O error occurs while either sending a
2907 * command to the server or receiving a reply
2908 * from the server.
2909 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
2910 * Thrown if the parserKey parameter cannot be
2911 * resolved by the selected parser factory.
2912 * In the DefaultFTPEntryParserFactory, this will
2913 * happen when parserKey is neither
2914 * the fully qualified class name of a class
2915 * implementing the interface
2916 * org.apache.commons.net.ftp.FTPFileEntryParser
2917 * nor a string containing one of the recognized keys
2918 * mapping to such a parser or if class loader
2919 * security issues prevent its being loaded.
2920 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2921 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2922 * @see org.apache.commons.net.ftp.FTPFileEntryParser
2923 */
2924 public FTPFile[] listFiles(String pathname)
2925 throws IOException
2926 {
2927 FTPListParseEngine engine = initiateListParsing((String) null, pathname);
2928 return engine.getFiles();
2929
2930 }
2931
2932 /**
2933 * Using the default system autodetect mechanism, obtain a
2934 * list of file information for the current working directory.
2935 * <p>
2936 * This information is obtained through the LIST command. The contents of
2937 * the returned array is determined by the<code> FTPFileEntryParser </code>
2938 * used.
2939 * <p>
2940 * @return The list of file information contained in the current directory
2941 * in the format determined by the autodetection mechanism.
2942 * <p><b>
2943 * NOTE:</b> This array may contain null members if any of the
2944 * individual file listings failed to parse. The caller should
2945 * check each entry for null before referencing it.
2946 * @exception FTPConnectionClosedException
2947 * If the FTP server prematurely closes the connection
2948 * as a result of the client being idle or some other
2949 * reason causing the server to send FTP reply code 421.
2950 * This exception may be caught either as an IOException
2951 * or independently as itself.
2952 * @exception IOException
2953 * If an I/O error occurs while either sending a
2954 * command to the server or receiving a reply
2955 * from the server.
2956 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
2957 * Thrown if the parserKey parameter cannot be
2958 * resolved by the selected parser factory.
2959 * In the DefaultFTPEntryParserFactory, this will
2960 * happen when parserKey is neither
2961 * the fully qualified class name of a class
2962 * implementing the interface
2963 * org.apache.commons.net.ftp.FTPFileEntryParser
2964 * nor a string containing one of the recognized keys
2965 * mapping to such a parser or if class loader
2966 * security issues prevent its being loaded.
2967 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2968 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2969 * @see org.apache.commons.net.ftp.FTPFileEntryParser
2970 */
2971 public FTPFile[] listFiles()
2972 throws IOException
2973 {
2974 return listFiles((String) null);
2975 }
2976
2977 /**
2978 * Version of {@link #listFiles(String)} which allows a filter to be provided.
2979 * For example: <code>listFiles("site", FTPFileFilters.DIRECTORY);</code>
2980 * @param pathname the initial path, may be null
2981 * @param filter the filter, non-null
2982 * @return the list of FTPFile entries.
2983 * @throws IOException
2984 * @since 2.2
2985 */
2986 public FTPFile[] listFiles(String pathname, FTPFileFilter filter)
2987 throws IOException
2988 {
2989 FTPListParseEngine engine = initiateListParsing((String) null, pathname);
2990 return engine.getFiles(filter);
2991
2992 }
2993
2994 /**
2995 * Using the default system autodetect mechanism, obtain a
2996 * list of directories contained in the current working directory.
2997 * <p>
2998 * This information is obtained through the LIST command. The contents of
2999 * the returned array is determined by the<code> FTPFileEntryParser </code>
3000 * used.
3001 * <p>
3002 * @return The list of directories contained in the current directory
3003 * in the format determined by the autodetection mechanism.
3004 *
3005 * @exception FTPConnectionClosedException
3006 * If the FTP server prematurely closes the connection
3007 * as a result of the client being idle or some other
3008 * reason causing the server to send FTP reply code 421.
3009 * This exception may be caught either as an IOException
3010 * or independently as itself.
3011 * @exception IOException
3012 * If an I/O error occurs while either sending a
3013 * command to the server or receiving a reply
3014 * from the server.
3015 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
3016 * Thrown if the parserKey parameter cannot be
3017 * resolved by the selected parser factory.
3018 * In the DefaultFTPEntryParserFactory, this will
3019 * happen when parserKey is neither
3020 * the fully qualified class name of a class
3021 * implementing the interface
3022 * org.apache.commons.net.ftp.FTPFileEntryParser
3023 * nor a string containing one of the recognized keys
3024 * mapping to such a parser or if class loader
3025 * security issues prevent its being loaded.
3026 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
3027 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
3028 * @see org.apache.commons.net.ftp.FTPFileEntryParser
3029 * @since 3.0
3030 */
3031 public FTPFile[] listDirectories() throws IOException {
3032 return listDirectories((String) null);
3033 }
3034
3035 /**
3036 * Using the default system autodetect mechanism, obtain a
3037 * list of directories contained in the specified directory.
3038 * <p>
3039 * This information is obtained through the LIST command. The contents of
3040 * the returned array is determined by the<code> FTPFileEntryParser </code>
3041 * used.
3042 * <p>
3043 * @return The list of directories contained in the specified directory
3044 * in the format determined by the autodetection mechanism.
3045 *
3046 * @exception FTPConnectionClosedException
3047 * If the FTP server prematurely closes the connection
3048 * as a result of the client being idle or some other
3049 * reason causing the server to send FTP reply code 421.
3050 * This exception may be caught either as an IOException
3051 * or independently as itself.
3052 * @exception IOException
3053 * If an I/O error occurs while either sending a
3054 * command to the server or receiving a reply
3055 * from the server.
3056 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
3057 * Thrown if the parserKey parameter cannot be
3058 * resolved by the selected parser factory.
3059 * In the DefaultFTPEntryParserFactory, this will
3060 * happen when parserKey is neither
3061 * the fully qualified class name of a class
3062 * implementing the interface
3063 * org.apache.commons.net.ftp.FTPFileEntryParser
3064 * nor a string containing one of the recognized keys
3065 * mapping to such a parser or if class loader
3066 * security issues prevent its being loaded.
3067 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
3068 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
3069 * @see org.apache.commons.net.ftp.FTPFileEntryParser
3070 * @since 3.0
3071 */
3072 public FTPFile[] listDirectories(String parent) throws IOException {
3073 return listFiles(parent, FTPFileFilters.DIRECTORIES);
3074 }
3075
3076 /**
3077 * Using the default autodetect mechanism, initialize an FTPListParseEngine
3078 * object containing a raw file information for the current working
3079 * directory on the server
3080 * This information is obtained through the LIST command. This object
3081 * is then capable of being iterated to return a sequence of FTPFile
3082 * objects with information filled in by the
3083 * <code> FTPFileEntryParser </code> used.
3084 * <p>
3085 * This method differs from using the listFiles() methods in that
3086 * expensive FTPFile objects are not created until needed which may be
3087 * an advantage on large lists.
3088 *
3089 * @return A FTPListParseEngine object that holds the raw information and
3090 * is capable of providing parsed FTPFile objects, one for each file
3091 * containing information contained in the given path in the format
3092 * determined by the <code> parser </code> parameter. Null will be
3093 * returned if a data connection cannot be opened. If the current working
3094 * directory contains no files, an empty array will be the return.
3095 *
3096 * @exception FTPConnectionClosedException
3097 * If the FTP server prematurely closes the connection as a result
3098 * of the client being idle or some other reason causing the server
3099 * to send FTP reply code 421. This exception may be caught either
3100 * as an IOException or independently as itself.
3101 * @exception IOException
3102 * If an I/O error occurs while either sending a
3103 * command to the server or receiving a reply from the server.
3104 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
3105 * Thrown if the autodetect mechanism cannot
3106 * resolve the type of system we are connected with.
3107 * @see FTPListParseEngine
3108 */
3109 public FTPListParseEngine initiateListParsing()
3110 throws IOException
3111 {
3112 return initiateListParsing((String) null);
3113 }
3114
3115 /**
3116 * Using the default autodetect mechanism, initialize an FTPListParseEngine
3117 * object containing a raw file information for the supplied directory.
3118 * This information is obtained through the LIST command. This object
3119 * is then capable of being iterated to return a sequence of FTPFile
3120 * objects with information filled in by the
3121 * <code> FTPFileEntryParser </code> used.
3122 * <p>
3123 * The server may or may not expand glob expressions. You should avoid
3124 * using glob expressions because the return format for glob listings
3125 * differs from server to server and will likely cause this method to fail.
3126 * <p>
3127 * This method differs from using the listFiles() methods in that
3128 * expensive FTPFile objects are not created until needed which may be
3129 * an advantage on large lists.
3130 * <p>
3131 * <pre>
3132 * FTPClient f=FTPClient();
3133 * f.connect(server);
3134 * f.login(username, password);
3135 * FTPListParseEngine engine = f.initiateListParsing(directory);
3136 *
3137 * while (engine.hasNext()) {
3138 * FTPFile[] files = engine.getNext(25); // "page size" you want
3139 * //do whatever you want with these files, display them, etc.
3140 * //expensive FTPFile objects not created until needed.
3141 * }
3142 * </pre>
3143 *
3144 * @return A FTPListParseEngine object that holds the raw information and
3145 * is capable of providing parsed FTPFile objects, one for each file
3146 * containing information contained in the given path in the format
3147 * determined by the <code> parser </code> parameter. Null will be
3148 * returned if a data connection cannot be opened. If the current working
3149 * directory contains no files, an empty array will be the return.
3150 *
3151 * @exception FTPConnectionClosedException
3152 * If the FTP server prematurely closes the connection as a result
3153 * of the client being idle or some other reason causing the server
3154 * to send FTP reply code 421. This exception may be caught either
3155 * as an IOException or independently as itself.
3156 * @exception IOException
3157 * If an I/O error occurs while either sending a
3158 * command to the server or receiving a reply from the server.
3159 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
3160 * Thrown if the autodetect mechanism cannot
3161 * resolve the type of system we are connected with.
3162 * @see FTPListParseEngine
3163 */
3164 public FTPListParseEngine initiateListParsing(
3165 String pathname)
3166 throws IOException
3167 {
3168 return initiateListParsing((String) null, pathname);
3169 }
3170
3171 /**
3172 * Using the supplied parser key, initialize an FTPListParseEngine
3173 * object containing a raw file information for the supplied directory.
3174 * This information is obtained through the LIST command. This object
3175 * is then capable of being iterated to return a sequence of FTPFile
3176 * objects with information filled in by the
3177 * <code> FTPFileEntryParser </code> used.
3178 * <p>
3179 * The server may or may not expand glob expressions. You should avoid
3180 * using glob expressions because the return format for glob listings
3181 * differs from server to server and will likely cause this method to fail.
3182 * <p>
3183 * This method differs from using the listFiles() methods in that
3184 * expensive FTPFile objects are not created until needed which may be
3185 * an advantage on large lists.
3186 *
3187 * @param parserKey A string representing a designated code or fully-qualified
3188 * class name of an <code> FTPFileEntryParser </code> that should be
3189 * used to parse each server file listing.
3190 * May be {@code null}, in which case the code checks first
3191 * the system property {@link #FTP_SYSTEM_TYPE}, and if that is
3192 * not defined the SYST command is used to provide the value.
3193 * To allow for arbitrary system types, the return from the
3194 * SYST command is used to look up an alias for the type in the
3195 * {@link #SYSTEM_TYPE_PROPERTIES} properties file if it is available.
3196 *
3197 * @return A FTPListParseEngine object that holds the raw information and
3198 * is capable of providing parsed FTPFile objects, one for each file
3199 * containing information contained in the given path in the format
3200 * determined by the <code> parser </code> parameter. Null will be
3201 * returned if a data connection cannot be opened. If the current working
3202 * directory contains no files, an empty array will be the return.
3203 *
3204 * @exception FTPConnectionClosedException
3205 * If the FTP server prematurely closes the connection as a result
3206 * of the client being idle or some other reason causing the server
3207 * to send FTP reply code 421. This exception may be caught either
3208 * as an IOException or independently as itself.
3209 * @exception IOException
3210 * If an I/O error occurs while either sending a
3211 * command to the server or receiving a reply from the server.
3212 * @exception org.apache.commons.net.ftp.parser.ParserInitializationException
3213 * Thrown if the parserKey parameter cannot be
3214 * resolved by the selected parser factory.
3215 * In the DefaultFTPEntryParserFactory, this will
3216 * happen when parserKey is neither
3217 * the fully qualified class name of a class
3218 * implementing the interface
3219 * org.apache.commons.net.ftp.FTPFileEntryParser
3220 * nor a string containing one of the recognized keys
3221 * mapping to such a parser or if class loader
3222 * security issues prevent its being loaded.
3223 * @see FTPListParseEngine
3224 */
3225 public FTPListParseEngine initiateListParsing(
3226 String parserKey, String pathname)
3227 throws IOException
3228 {
3229 // We cache the value to avoid creation of a new object every
3230 // time a file listing is generated.
3231 if(__entryParser == null || ! __entryParserKey.equals(parserKey)) {
3232 if (null != parserKey) {
3233 // if a parser key was supplied in the parameters,
3234 // use that to create the parser
3235 __entryParser =
3236 __parserFactory.createFileEntryParser(parserKey);
3237 __entryParserKey = parserKey;
3238
3239 } else {
3240 // if no parserKey was supplied, check for a configuration
3241 // in the params, and if non-null, use that.
3242 if (null != __configuration) {
3243 __entryParser =
3244 __parserFactory.createFileEntryParser(__configuration);
3245 __entryParserKey = __configuration.getServerSystemKey();
3246 } else {
3247 // if a parserKey hasn't been supplied, and a configuration
3248 // hasn't been supplied, and the override property is not set
3249 // then autodetect by calling
3250 // the SYST command and use that to choose the parser.
3251 String systemType = System.getProperty(FTP_SYSTEM_TYPE);
3252 if (systemType == null) {
3253 systemType = getSystemType(); // cannot be null
3254 Properties override = getOverrideProperties();
3255 if (override != null) {
3256 String newType = override.getProperty(systemType);
3257 if (newType != null) {
3258 systemType = newType;
3259 }
3260 }
3261 }
3262 __entryParser = __parserFactory.createFileEntryParser(systemType);
3263 __entryParserKey = systemType;
3264 }
3265 }
3266 }
3267
3268 return initiateListParsing(__entryParser, pathname);
3269
3270 }
3271
3272 /**
3273 * private method through which all listFiles() and
3274 * initiateListParsing methods pass once a parser is determined.
3275 *
3276 * @exception FTPConnectionClosedException
3277 * If the FTP server prematurely closes the connection as a result
3278 * of the client being idle or some other reason causing the server
3279 * to send FTP reply code 421. This exception may be caught either
3280 * as an IOException or independently as itself.
3281 * @exception IOException
3282 * If an I/O error occurs while either sending a
3283 * command to the server or receiving a reply from the server.
3284 * @see FTPListParseEngine
3285 */
3286 private FTPListParseEngine initiateListParsing(
3287 FTPFileEntryParser parser, String pathname)
3288 throws IOException
3289 {
3290 Socket socket = _openDataConnection_(FTPCmd.LIST, getListArguments(pathname));
3291
3292 FTPListParseEngine engine = new FTPListParseEngine(parser);
3293 if (socket == null)
3294 {
3295 return engine;
3296 }
3297
3298 try {
3299 engine.readServerList(socket.getInputStream(), getControlEncoding());
3300 }
3301 finally {
3302 Util.closeQuietly(socket);
3303 }
3304
3305 completePendingCommand();
3306 return engine;
3307 }
3308
3309 /**
3310 * Initiate list parsing for MLSD listings.
3311 *
3312 * @param pathname
3313 * @return the engine
3314 * @throws IOException
3315 */
3316 private FTPListParseEngine initiateMListParsing(String pathname) throws IOException
3317 {
3318 Socket socket = _openDataConnection_(FTPCmd.MLSD, pathname);
3319 FTPListParseEngine engine = new FTPListParseEngine(MLSxEntryParser.getInstance());
3320 if (socket == null)
3321 {
3322 return engine;
3323 }
3324
3325 try {
3326 engine.readServerList(socket.getInputStream(), getControlEncoding());
3327 }
3328 finally {
3329 Util.closeQuietly(socket);
3330 completePendingCommand();
3331 }
3332 return engine;
3333 }
3334
3335 /**
3336 * @since 2.0
3337 */
3338 protected String getListArguments(String pathname) {
3339 if (getListHiddenFiles())
3340 {
3341 if (pathname != null)
3342 {
3343 StringBuilder sb = new StringBuilder(pathname.length() + 3);
3344 sb.append("-a ");
3345 sb.append(pathname);
3346 return sb.toString();
3347 }
3348 else
3349 {
3350 return "-a";
3351 }
3352 }
3353
3354 return pathname;
3355 }
3356
3357
3358 /**
3359 * Issue the FTP STAT command to the server.
3360 * <p>
3361 * @return The status information returned by the server.
3362 * @exception FTPConnectionClosedException
3363 * If the FTP server prematurely closes the connection as a result
3364 * of the client being idle or some other reason causing the server
3365 * to send FTP reply code 421. This exception may be caught either
3366 * as an IOException or independently as itself.
3367 * @exception IOException If an I/O error occurs while either sending a
3368 * command to the server or receiving a reply from the server.
3369 */
3370 public String getStatus() throws IOException
3371 {
3372 if (FTPReply.isPositiveCompletion(stat())) {
3373 return getReplyString();
3374 }
3375 return null;
3376 }
3377
3378
3379 /**
3380 * Issue the FTP STAT command to the server for a given pathname. This
3381 * should produce a listing of the file or directory.
3382 * <p>
3383 * @return The status information returned by the server.
3384 * @exception FTPConnectionClosedException
3385 * If the FTP server prematurely closes the connection as a result
3386 * of the client being idle or some other reason causing the server
3387 * to send FTP reply code 421. This exception may be caught either
3388 * as an IOException or independently as itself.
3389 * @exception IOException If an I/O error occurs while either sending a
3390 * command to the server or receiving a reply from the server.
3391 */
3392 public String getStatus(String pathname) throws IOException
3393 {
3394 if (FTPReply.isPositiveCompletion(stat(pathname))) {
3395 return getReplyString();
3396 }
3397 return null;
3398 }
3399
3400
3401 /**
3402 * Issue the FTP MDTM command (not supported by all servers to retrieve the last
3403 * modification time of a file. The modification string should be in the
3404 * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in
3405 * GMT, but not all FTP servers honour this.
3406 *
3407 * @param pathname The file path to query.
3408 * @return A string representing the last file modification time in <code>YYYYMMDDhhmmss</code> format.
3409 * @throws IOException if an I/O error occurs.
3410 * @since 2.0
3411 */
3412 public String getModificationTime(String pathname) throws IOException {
3413 if (FTPReply.isPositiveCompletion(mdtm(pathname))) {
3414 return getReplyString();
3415 }
3416 return null;
3417 }
3418
3419
3420 /**
3421 * Issue the FTP MFMT command (not supported by all servers) which sets the last
3422 * modified time of a file.
3423 *
3424 * The timestamp should be in the form <code>YYYYMMDDhhmmss</code>. It should also
3425 * be in GMT, but not all servers honour this.
3426 *
3427 * An FTP server would indicate its support of this feature by including "MFMT"
3428 * in its response to the FEAT command, which may be retrieved by FTPClient.features()
3429 *
3430 * @param pathname The file path for which last modified time is to be changed.
3431 * @param timeval The timestamp to set to, in <code>YYYYMMDDhhmmss</code> format.
3432 * @return true if successfully set, false if not
3433 * @throws IOException if an I/O error occurs.
3434 * @since 2.2
3435 * @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a>
3436 */
3437 public boolean setModificationTime(String pathname, String timeval) throws IOException {
3438 return (FTPReply.isPositiveCompletion(mfmt(pathname, timeval)));
3439 }
3440
3441
3442 /**
3443 * Set the internal buffer size for buffered data streams.
3444 *
3445 * @param bufSize The size of the buffer. Use a non-positive value to use the default.
3446 */
3447 public void setBufferSize(int bufSize) {
3448 __bufferSize = bufSize;
3449 }
3450
3451 /**
3452 * Retrieve the current internal buffer size for buffered data streams.
3453 * @return The current buffer size.
3454 */
3455 public int getBufferSize() {
3456 return __bufferSize;
3457 }
3458
3459 /**
3460 * Sets the value to be used for the data socket SO_SNDBUF option.
3461 * If the value is positive, the option will be set when the data socket has been created.
3462 *
3463 * @param bufSize The size of the buffer, zero or negative means the value is ignored.
3464 * @since 3.3
3465 */
3466 public void setSendDataSocketBufferSize(int bufSize) {
3467 __sendDataSocketBufferSize = bufSize;
3468 }
3469
3470 /**
3471 * Retrieve the value to be used for the data socket SO_SNDBUF option.
3472 * @return The current buffer size.
3473 * @since 3.3
3474 */
3475 public int getSendDataSocketBufferSize() {
3476 return __sendDataSocketBufferSize;
3477 }
3478
3479 /**
3480 * Sets the value to be used for the data socket SO_RCVBUF option.
3481 * If the value is positive, the option will be set when the data socket has been created.
3482 *
3483 * @param bufSize The size of the buffer, zero or negative means the value is ignored.
3484 * @since 3.3
3485 */
3486 public void setReceieveDataSocketBufferSize(int bufSize) {
3487 __receiveDataSocketBufferSize = bufSize;
3488 }
3489
3490 /**
3491 * Retrieve the value to be used for the data socket SO_RCVBUF option.
3492 * @return The current buffer size.
3493 * @since 3.3
3494 */
3495 public int getReceiveDataSocketBufferSize() {
3496 return __receiveDataSocketBufferSize;
3497 }
3498
3499 /**
3500 * Implementation of the {@link Configurable Configurable} interface.
3501 * In the case of this class, configuring merely makes the config object available for the
3502 * factory methods that construct parsers.
3503 * @param config {@link FTPClientConfig FTPClientConfig} object used to
3504 * provide non-standard configurations to the parser.
3505 * @since 1.4
3506 */
3507 @Override
3508 public void configure(FTPClientConfig config) {
3509 this.__configuration = config;
3510 }
3511
3512 /**
3513 * You can set this to true if you would like to get hidden files when {@link #listFiles} too.
3514 * A <code>LIST -a</code> will be issued to the ftp server.
3515 * It depends on your ftp server if you need to call this method, also dont expect to get rid
3516 * of hidden files if you call this method with "false".
3517 *
3518 * @param listHiddenFiles true if hidden files should be listed
3519 * @since 2.0
3520 */
3521 public void setListHiddenFiles(boolean listHiddenFiles) {
3522 this.__listHiddenFiles = listHiddenFiles;
3523 }
3524
3525 /**
3526 * @see #setListHiddenFiles(boolean)
3527 * @return the current state
3528 * @since 2.0
3529 */
3530 public boolean getListHiddenFiles() {
3531 return this.__listHiddenFiles;
3532 }
3533
3534 /**
3535 * Whether should attempt to use EPSV with IPv4.
3536 * Default (if not set) is <code>false</code>
3537 * @return true if should attempt EPSV
3538 * @since 2.2
3539 */
3540 public boolean isUseEPSVwithIPv4() {
3541 return __useEPSVwithIPv4;
3542 }
3543
3544
3545 /**
3546 * Set whether to use EPSV with IPv4.
3547 * Might be worth enabling in some circumstances.
3548 *
3549 * For example, when using IPv4 with NAT it
3550 * may work with some rare configurations.
3551 * E.g. if FTP server has a static PASV address (external network)
3552 * and the client is coming from another internal network.
3553 * In that case the data connection after PASV command would fail,
3554 * while EPSV would make the client succeed by taking just the port.
3555 *
3556 * @param selected value to set.
3557 * @since 2.2
3558 */
3559 public void setUseEPSVwithIPv4(boolean selected) {
3560 this.__useEPSVwithIPv4 = selected;
3561 }
3562
3563 /**
3564 * Set the listener to be used when performing store/retrieve operations.
3565 * The default value (if not set) is {@code null}.
3566 *
3567 * @param listener to be used, may be {@code null} to disable
3568 * @since 3.0
3569 */
3570 public void setCopyStreamListener(CopyStreamListener listener){
3571 __copyStreamListener = listener;
3572 }
3573
3574 /**
3575 * Obtain the currently active listener.
3576 *
3577 * @return the listener, may be {@code null}
3578 * @since 3.0
3579 */
3580 public CopyStreamListener getCopyStreamListener(){
3581 return __copyStreamListener;
3582 }
3583
3584 /**
3585 * Set the time to wait between sending control connection keepalive messages
3586 * when processing file upload or download.
3587 *
3588 * @param controlIdle the wait (in secs) between keepalive messages. Zero (or less) disables.
3589 * @since 3.0
3590 * @see #setControlKeepAliveReplyTimeout(int)
3591 */
3592 public void setControlKeepAliveTimeout(long controlIdle){
3593 __controlKeepAliveTimeout = controlIdle * 1000;
3594 }
3595
3596 /**
3597 * Get the time to wait between sending control connection keepalive messages.
3598 * @return the number of seconds between keepalive messages.
3599 * @since 3.0
3600 */
3601 public long getControlKeepAliveTimeout() {
3602 return __controlKeepAliveTimeout / 1000;
3603 }
3604
3605 /**
3606 * Set how long to wait for control keep-alive message replies.
3607 *
3608 * @param timeout number of milliseconds to wait (defaults to 1000)
3609 * @since 3.0
3610 * @see #setControlKeepAliveTimeout(long)
3611 */
3612 public void setControlKeepAliveReplyTimeout(int timeout) {
3613 __controlKeepAliveReplyTimeout = timeout;
3614 }
3615
3616 /**
3617 * Get how long to wait for control keep-alive message replies.
3618 * @since 3.0
3619 */
3620 public int getControlKeepAliveReplyTimeout() {
3621 return __controlKeepAliveReplyTimeout;
3622 }
3623
3624 private OutputStream getBufferedOutputStream(OutputStream outputStream) {
3625 if (__bufferSize > 0) {
3626 return new BufferedOutputStream(outputStream, __bufferSize);
3627 }
3628 return new BufferedOutputStream(outputStream);
3629 }
3630
3631 private InputStream getBufferedInputStream(InputStream inputStream) {
3632 if (__bufferSize > 0) {
3633 return new BufferedInputStream(inputStream, __bufferSize);
3634 }
3635 return new BufferedInputStream(inputStream);
3636 }
3637
3638 // @since 3.0
3639 private static class CSL implements CopyStreamListener {
3640
3641 private final FTPClient parent;
3642 private final long idle;
3643 private final int currentSoTimeout;
3644
3645 private long time = System.currentTimeMillis();
3646 private int notAcked;
3647
3648 CSL(FTPClient parent, long idleTime, int maxWait) throws SocketException {
3649 this.idle = idleTime;
3650 this.parent = parent;
3651 this.currentSoTimeout = parent.getSoTimeout();
3652 parent.setSoTimeout(maxWait);
3653 }
3654
3655 @Override
3656 public void bytesTransferred(CopyStreamEvent event) {
3657 bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize());
3658 }
3659
3660 @Override
3661 public void bytesTransferred(long totalBytesTransferred,
3662 int bytesTransferred, long streamSize) {
3663 long now = System.currentTimeMillis();
3664 if (now - time > idle) {
3665 try {
3666 parent.__noop();
3667 } catch (SocketTimeoutException e) {
3668 notAcked++;
3669 } catch (IOException e) {
3670 }
3671 time = now;
3672 }
3673 }
3674
3675 void cleanUp() throws IOException {
3676 try {
3677 while(notAcked-- > 0) {
3678 parent.__getReplyNoReport();
3679 }
3680 } finally {
3681 parent.setSoTimeout(currentSoTimeout);
3682 }
3683 }
3684
3685 }
3686
3687 /**
3688 * Merge two copystream listeners, either or both of which may be null.
3689 *
3690 * @param local the listener used by this class, may be null
3691 * @return a merged listener or a single listener or null
3692 * @since 3.0
3693 */
3694 private CopyStreamListener __mergeListeners(CopyStreamListener local) {
3695 if (local == null) {
3696 return __copyStreamListener;
3697 }
3698 if (__copyStreamListener == null) {
3699 return local;
3700 }
3701 // Both are non-null
3702 CopyStreamAdapter merged = new CopyStreamAdapter();
3703 merged.addCopyStreamListener(local);
3704 merged.addCopyStreamListener(__copyStreamListener);
3705 return merged;
3706 }
3707
3708 /**
3709 * Enables or disables automatic server encoding detection (only UTF-8 supported).
3710 * <p>
3711 * Does not affect existing connections; must be invoked before a connection is established.
3712 *
3713 * @param autodetect If true, automatic server encoding detection will be enabled.
3714 */
3715 public void setAutodetectUTF8(boolean autodetect)
3716 {
3717 __autodetectEncoding = autodetect;
3718 }
3719
3720 /**
3721 * Tells if automatic server encoding detection is enabled or disabled.
3722 * @return true, if automatic server encoding detection is enabled.
3723 */
3724 public boolean getAutodetectUTF8()
3725 {
3726 return __autodetectEncoding;
3727 }
3728
3729 // DEPRECATED METHODS - for API compatibility only - DO NOT USE
3730
3731 /**
3732 * @deprecated use {@link #getSystemType()} instead
3733 */
3734 @Deprecated
3735 public String getSystemName() throws IOException
3736 {
3737 if (__systemName == null && FTPReply.isPositiveCompletion(syst())) {
3738 __systemName = _replyLines.get(_replyLines.size() - 1).substring(4);
3739 }
3740 return __systemName;
3741 }
3742 }
3743
3744 /* Emacs configuration
3745 * Local variables: **
3746 * mode: java **
3747 * c-basic-offset: 4 **
3748 * indent-tabs-mode: nil **
3749 * End: **
3750 */
3751 /* kate: indent-width 4; replace-tabs on; */