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