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