View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package examples.ftp;
19  
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.io.PrintWriter;
26  import java.net.InetAddress;
27  import java.net.UnknownHostException;
28  import java.util.Arrays;
29  
30  import org.apache.commons.net.PrintCommandListener;
31  import org.apache.commons.net.ftp.FTP;
32  import org.apache.commons.net.ftp.FTPClient;
33  import org.apache.commons.net.ftp.FTPHTTPClient;
34  import org.apache.commons.net.ftp.FTPClientConfig;
35  import org.apache.commons.net.ftp.FTPConnectionClosedException;
36  import org.apache.commons.net.ftp.FTPFile;
37  import org.apache.commons.net.ftp.FTPReply;
38  import org.apache.commons.net.ftp.FTPSClient;
39  import org.apache.commons.net.io.CopyStreamEvent;
40  import org.apache.commons.net.io.CopyStreamListener;
41  import org.apache.commons.net.util.TrustManagerUtils;
42  
43  /**
44   * This is an example program demonstrating how to use the FTPClient class.
45   * This program connects to an FTP server and retrieves the specified
46   * file.  If the -s flag is used, it stores the local file at the FTP server.
47   * Just so you can see what's happening, all reply strings are printed.
48   * If the -b flag is used, a binary transfer is assumed (default is ASCII).
49   * See below for further options.
50   */
51  public final class FTPClientExample
52  {
53  
54      public static final String USAGE =
55          "Expected Parameters: [options] <hostname> <username> <password> [<remote file> [<local file>]]\n" +
56          "\nDefault behavior is to download a file and use ASCII transfer mode.\n" +
57          "\t-a - use local active mode (default is local passive)\n" +
58          "\t-A - anonymous login (omit username and password parameters)\n" +
59          "\t-b - use binary transfer mode\n" +
60          "\t-c cmd - issue arbitrary command (remote is used as a parameter if provided) \n" +
61          "\t-d - list directory details using MLSD (remote is used as the pathname if provided)\n" +
62          "\t-e - use EPSV with IPv4 (default false)\n" +
63          "\t-E - encoding to use for control channel\n" +
64          "\t-f - issue FEAT command (remote and local files are ignored)\n" +
65          "\t-h - list hidden files (applies to -l and -n only)\n" +
66          "\t-k secs - use keep-alive timer (setControlKeepAliveTimeout)\n" +
67          "\t-l - list files using LIST (remote is used as the pathname if provided)\n" +
68          "\t     Files are listed twice: first in raw mode, then as the formatted parsed data.\n" +
69          "\t     N.B. if the wrong server-type is used, output may be lost. Use -U or -S as necessary.\n" +
70          "\t-L - use lenient future dates (server dates may be up to 1 day into future)\n" +
71          "\t-m - list file details using MDTM (remote is used as the pathname if provided)\n" +
72          "\t-n - list file names using NLST (remote is used as the pathname if provided)\n" +
73          "\t-p true|false|protocol[,true|false] - use FTPSClient with the specified protocol and/or isImplicit setting\n" +
74          "\t-s - store file on server (upload)\n" +
75          "\t-S - systemType set server system type (e.g. UNIX VMS WINDOWS)\n" +
76          "\t-t - list file details using MLST (remote is used as the pathname if provided)\n" +
77          "\t-U - save unparseable responses\n" +
78          "\t-w msec - wait time for keep-alive reply (setControlKeepAliveReplyTimeout)\n" +
79          "\t-T  all|valid|none - use one of the built-in TrustManager implementations (none = JVM default)\n" +
80          "\t-y format - set default date format string\n" +
81          "\t-Y format - set recent date format string\n" +
82          "\t-Z timezone - set the server timezone for parsing LIST responses\n" +
83          "\t-z timezone - set the timezone for displaying MDTM, LIST, MLSD, MLST responses\n" +
84          "\t-PrH server[:port] - HTTP Proxy host and optional port[80] \n" +
85          "\t-PrU user - HTTP Proxy server username\n" +
86          "\t-PrP password - HTTP Proxy server password\n" +
87          "\t-# - add hash display during transfers\n";
88  
89      public static void main(String[] args) throws UnknownHostException
90      {
91          boolean storeFile = false, binaryTransfer = false, error = false, listFiles = false, listNames = false, hidden = false;
92          boolean localActive = false, useEpsvWithIPv4 = false, feat = false, printHash = false;
93          boolean mlst = false, mlsd = false, mdtm = false, saveUnparseable = false;
94          boolean lenient = false;
95          long keepAliveTimeout = -1;
96          int controlKeepAliveReplyTimeout = -1;
97          int minParams = 5; // listings require 3 params
98          String protocol = null; // SSL protocol
99          String doCommand = null;
100         String trustmgr = null;
101         String proxyHost = null;
102         int proxyPort = 80;
103         String proxyUser = null;
104         String proxyPassword = null;
105         String username = null;
106         String password = null;
107         String encoding = null;
108         String serverTimeZoneId = null;
109         String displayTimeZoneId = null;
110         String serverType = null;
111         String defaultDateFormat = null;
112         String recentDateFormat = null;
113 
114 
115         int base = 0;
116         for (base = 0; base < args.length; base++)
117         {
118             if (args[base].equals("-s")) {
119                 storeFile = true;
120             }
121             else if (args[base].equals("-a")) {
122                 localActive = true;
123             }
124             else if (args[base].equals("-A")) {
125                 username = "anonymous";
126                 password = System.getProperty("user.name")+"@"+InetAddress.getLocalHost().getHostName();
127             }
128             else if (args[base].equals("-b")) {
129                 binaryTransfer = true;
130             }
131             else if (args[base].equals("-c")) {
132                 doCommand = args[++base];
133                 minParams = 3;
134             }
135             else if (args[base].equals("-d")) {
136                 mlsd = true;
137                 minParams = 3;
138             }
139             else if (args[base].equals("-e")) {
140                 useEpsvWithIPv4 = true;
141             }
142             else if (args[base].equals("-E")) {
143                 encoding = args[++base];
144             }
145             else if (args[base].equals("-f")) {
146                 feat = true;
147                 minParams = 3;
148             }
149             else if (args[base].equals("-h")) {
150                 hidden = true;
151             }
152             else if (args[base].equals("-k")) {
153                 keepAliveTimeout = Long.parseLong(args[++base]);
154             }
155             else if (args[base].equals("-l")) {
156                 listFiles = true;
157                 minParams = 3;
158             }
159             else if (args[base].equals("-m")) {
160                 mdtm = true;
161                 minParams = 3;
162             }
163             else if (args[base].equals("-L")) {
164                 lenient = true;
165             }
166             else if (args[base].equals("-n")) {
167                 listNames = true;
168                 minParams = 3;
169             }
170             else if (args[base].equals("-p")) {
171                 protocol = args[++base];
172             }
173             else if (args[base].equals("-S")) {
174                 serverType = args[++base];
175             }
176             else if (args[base].equals("-t")) {
177                 mlst = true;
178                 minParams = 3;
179             }
180             else if (args[base].equals("-U")) {
181                 saveUnparseable = true;
182             }
183             else if (args[base].equals("-w")) {
184                 controlKeepAliveReplyTimeout = Integer.parseInt(args[++base]);
185             }
186             else if (args[base].equals("-T")) {
187                 trustmgr = args[++base];
188             }
189             else if (args[base].equals("-y")) {
190                 defaultDateFormat = args[++base];
191             }
192             else if (args[base].equals("-Y")) {
193                 recentDateFormat = args[++base];
194             }
195             else if (args[base].equals("-Z")) {
196                 serverTimeZoneId = args[++base];
197             }
198             else if (args[base].equals("-z")) {
199                 displayTimeZoneId = args[++base];
200             }
201             else if (args[base].equals("-PrH")) {
202                 proxyHost = args[++base];
203                 String parts[] = proxyHost.split(":");
204                 if (parts.length == 2){
205                     proxyHost=parts[0];
206                     proxyPort=Integer.parseInt(parts[1]);
207                 }
208             }
209             else if (args[base].equals("-PrU")) {
210                 proxyUser = args[++base];
211             }
212             else if (args[base].equals("-PrP")) {
213                 proxyPassword = args[++base];
214             }
215             else if (args[base].equals("-#")) {
216                 printHash = true;
217             }
218             else {
219                 break;
220             }
221         }
222 
223         int remain = args.length - base;
224         if (username != null) {
225             minParams -= 2;
226         }
227         if (remain < minParams) // server, user, pass, remote, local [protocol]
228         {
229             if (args.length > 0) {
230                 System.err.println("Actual Parameters: " + Arrays.toString(args));
231             }
232             System.err.println(USAGE);
233             System.exit(1);
234         }
235 
236         String server = args[base++];
237         int port = 0;
238         String parts[] = server.split(":");
239         if (parts.length == 2){
240             server=parts[0];
241             port=Integer.parseInt(parts[1]);
242         }
243         if (username == null) {
244             username = args[base++];
245             password = args[base++];
246         }
247 
248         String remote = null;
249         if (args.length - base > 0) {
250             remote = args[base++];
251         }
252 
253         String local = null;
254         if (args.length - base > 0) {
255             local = args[base++];
256         }
257 
258         final FTPClient ftp;
259         if (protocol == null ) {
260             if(proxyHost !=null) {
261                 System.out.println("Using HTTP proxy server: " + proxyHost);
262                 ftp = new FTPHTTPClient(proxyHost, proxyPort, proxyUser, proxyPassword);
263             }
264             else {
265                 ftp = new FTPClient();
266             }
267         } else {
268             FTPSClient ftps;
269             if (protocol.equals("true")) {
270                 ftps = new FTPSClient(true);
271             } else if (protocol.equals("false")) {
272                 ftps = new FTPSClient(false);
273             } else {
274                 String prot[] = protocol.split(",");
275                 if (prot.length == 1) { // Just protocol
276                     ftps = new FTPSClient(protocol);
277                 } else { // protocol,true|false
278                     ftps = new FTPSClient(prot[0], Boolean.parseBoolean(prot[1]));
279                 }
280             }
281             ftp = ftps;
282             if ("all".equals(trustmgr)) {
283                 ftps.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
284             } else if ("valid".equals(trustmgr)) {
285                 ftps.setTrustManager(TrustManagerUtils.getValidateServerCertificateTrustManager());
286             } else if ("none".equals(trustmgr)) {
287                 ftps.setTrustManager(null);
288             }
289         }
290 
291         if (printHash) {
292             ftp.setCopyStreamListener(createListener());
293         }
294         if (keepAliveTimeout >= 0) {
295             ftp.setControlKeepAliveTimeout(keepAliveTimeout);
296         }
297         if (controlKeepAliveReplyTimeout >= 0) {
298             ftp.setControlKeepAliveReplyTimeout(controlKeepAliveReplyTimeout);
299         }
300         if (encoding != null) {
301             ftp.setControlEncoding(encoding);
302         }
303         ftp.setListHiddenFiles(hidden);
304 
305         // suppress login details
306         ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
307 
308         final FTPClientConfig config;
309         if (serverType != null) {
310             config = new FTPClientConfig(serverType);
311         } else {
312             config = new FTPClientConfig();
313         }
314         config.setUnparseableEntries(saveUnparseable);
315         if (defaultDateFormat != null) {
316             config.setDefaultDateFormatStr(defaultDateFormat);
317         }
318         if (recentDateFormat != null) {
319             config.setRecentDateFormatStr(recentDateFormat);
320         }
321         ftp.configure(config);
322 
323         try
324         {
325             int reply;
326             if (port > 0) {
327                 ftp.connect(server, port);
328             } else {
329                 ftp.connect(server);
330             }
331             System.out.println("Connected to " + server + " on " + (port>0 ? port : ftp.getDefaultPort()));
332 
333             // After connection attempt, you should check the reply code to verify
334             // success.
335             reply = ftp.getReplyCode();
336 
337             if (!FTPReply.isPositiveCompletion(reply))
338             {
339                 ftp.disconnect();
340                 System.err.println("FTP server refused connection.");
341                 System.exit(1);
342             }
343         }
344         catch (IOException e)
345         {
346             if (ftp.isConnected())
347             {
348                 try
349                 {
350                     ftp.disconnect();
351                 }
352                 catch (IOException f)
353                 {
354                     // do nothing
355                 }
356             }
357             System.err.println("Could not connect to server.");
358             e.printStackTrace();
359             System.exit(1);
360         }
361 
362 __main:
363         try
364         {
365             if (!ftp.login(username, password))
366             {
367                 ftp.logout();
368                 error = true;
369                 break __main;
370             }
371 
372             System.out.println("Remote system is " + ftp.getSystemType());
373 
374             if (binaryTransfer) {
375                 ftp.setFileType(FTP.BINARY_FILE_TYPE);
376             } else {
377                 // in theory this should not be necessary as servers should default to ASCII
378                 // but they don't all do so - see NET-500
379                 ftp.setFileType(FTP.ASCII_FILE_TYPE);
380             }
381 
382             // Use passive mode as default because most of us are
383             // behind firewalls these days.
384             if (localActive) {
385                 ftp.enterLocalActiveMode();
386             } else {
387                 ftp.enterLocalPassiveMode();
388             }
389 
390             ftp.setUseEPSVwithIPv4(useEpsvWithIPv4);
391 
392             if (storeFile)
393             {
394                 InputStream input;
395 
396                 input = new FileInputStream(local);
397 
398                 ftp.storeFile(remote, input);
399 
400                 input.close();
401             }
402             // Allow multiple list types for single invocation
403             else if (listFiles || mlsd || mdtm || mlst || listNames)
404             {
405                 if (mlsd) {
406                     for (FTPFile f : ftp.mlistDir(remote)) {
407                         System.out.println(f.getRawListing());
408                         System.out.println(f.toFormattedString(displayTimeZoneId));
409                     }
410                 }
411                 if (mdtm) {
412                     FTPFile f = ftp.mdtmFile(remote);
413                     System.out.println(f.getRawListing());
414                     System.out.println(f.toFormattedString(displayTimeZoneId));
415                 }
416                 if (mlst) {
417                     FTPFile f = ftp.mlistFile(remote);
418                     if (f != null){
419                         System.out.println(f.toFormattedString(displayTimeZoneId));
420                     }
421                 }
422                 if (listNames) {
423                     for (String s : ftp.listNames(remote)) {
424                         System.out.println(s);
425                     }
426                 }
427                 // Do this last because it changes the client
428                 if (listFiles) {
429                     if (lenient || serverTimeZoneId != null) {
430                         config.setLenientFutureDates(lenient);
431                         if (serverTimeZoneId != null) {
432                             config.setServerTimeZoneId(serverTimeZoneId);
433                         }
434                         ftp.configure(config );
435                     }
436 
437                     for (FTPFile f : ftp.listFiles(remote)) {
438                         System.out.println(f.getRawListing());
439                         System.out.println(f.toFormattedString(displayTimeZoneId));
440                     }
441                 }
442             }
443             else if (feat)
444             {
445                 // boolean feature check
446                 if (remote != null) { // See if the command is present
447                     if (ftp.hasFeature(remote)) {
448                         System.out.println("Has feature: "+remote);
449                     } else {
450                         if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
451                             System.out.println("FEAT "+remote+" was not detected");
452                         } else {
453                             System.out.println("Command failed: "+ftp.getReplyString());
454                         }
455                     }
456 
457                     // Strings feature check
458                     String []features = ftp.featureValues(remote);
459                     if (features != null) {
460                         for(String f : features) {
461                             System.out.println("FEAT "+remote+"="+f+".");
462                         }
463                     } else {
464                         if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
465                             System.out.println("FEAT "+remote+" is not present");
466                         } else {
467                             System.out.println("Command failed: "+ftp.getReplyString());
468                         }
469                     }
470                 } else {
471                     if (ftp.features()) {
472 //                        Command listener has already printed the output
473                     } else {
474                         System.out.println("Failed: "+ftp.getReplyString());
475                     }
476                 }
477             }
478             else if (doCommand != null)
479             {
480                 if (ftp.doCommand(doCommand, remote)) {
481 //                  Command listener has already printed the output
482 //                    for(String s : ftp.getReplyStrings()) {
483 //                        System.out.println(s);
484 //                    }
485                 } else {
486                     System.out.println("Failed: "+ftp.getReplyString());
487                 }
488             }
489             else
490             {
491                 OutputStream output;
492 
493                 output = new FileOutputStream(local);
494 
495                 ftp.retrieveFile(remote, output);
496 
497                 output.close();
498             }
499 
500             ftp.noop(); // check that control connection is working OK
501 
502             ftp.logout();
503         }
504         catch (FTPConnectionClosedException e)
505         {
506             error = true;
507             System.err.println("Server closed connection.");
508             e.printStackTrace();
509         }
510         catch (IOException e)
511         {
512             error = true;
513             e.printStackTrace();
514         }
515         finally
516         {
517             if (ftp.isConnected())
518             {
519                 try
520                 {
521                     ftp.disconnect();
522                 }
523                 catch (IOException f)
524                 {
525                     // do nothing
526                 }
527             }
528         }
529 
530         System.exit(error ? 1 : 0);
531     } // end main
532 
533     private static CopyStreamListener createListener(){
534         return new CopyStreamListener(){
535             private long megsTotal = 0;
536 
537             @Override
538             public void bytesTransferred(CopyStreamEvent event) {
539                 bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize());
540             }
541 
542             @Override
543             public void bytesTransferred(long totalBytesTransferred,
544                     int bytesTransferred, long streamSize) {
545                 long megs = totalBytesTransferred / 1000000;
546                 for (long l = megsTotal; l < megs; l++) {
547                     System.err.print("#");
548                 }
549                 megsTotal = megs;
550             }
551         };
552     }
553 }
554