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 018package examples.ftp; 019 020import java.io.FileInputStream; 021import java.io.FileOutputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025import java.io.PrintWriter; 026import java.net.InetAddress; 027import java.net.UnknownHostException; 028import java.util.Arrays; 029 030import org.apache.commons.net.PrintCommandListener; 031import org.apache.commons.net.ftp.FTP; 032import org.apache.commons.net.ftp.FTPClient; 033import org.apache.commons.net.ftp.FTPHTTPClient; 034import org.apache.commons.net.ftp.FTPClientConfig; 035import org.apache.commons.net.ftp.FTPConnectionClosedException; 036import org.apache.commons.net.ftp.FTPFile; 037import org.apache.commons.net.ftp.FTPReply; 038import org.apache.commons.net.ftp.FTPSClient; 039import org.apache.commons.net.io.CopyStreamEvent; 040import org.apache.commons.net.io.CopyStreamListener; 041import org.apache.commons.net.util.TrustManagerUtils; 042 043/** 044 * This is an example program demonstrating how to use the FTPClient class. 045 * This program connects to an FTP server and retrieves the specified 046 * file. If the -s flag is used, it stores the local file at the FTP server. 047 * Just so you can see what's happening, all reply strings are printed. 048 * If the -b flag is used, a binary transfer is assumed (default is ASCII). 049 * See below for further options. 050 */ 051public final class FTPClientExample 052{ 053 054 public static final String USAGE = 055 "Expected Parameters: [options] <hostname> <username> <password> [<remote file> [<local file>]]\n" + 056 "\nDefault behavior is to download a file and use ASCII transfer mode.\n" + 057 "\t-a - use local active mode (default is local passive)\n" + 058 "\t-A - anonymous login (omit username and password parameters)\n" + 059 "\t-b - use binary transfer mode\n" + 060 "\t-c cmd - issue arbitrary command (remote is used as a parameter if provided) \n" + 061 "\t-d - list directory details using MLSD (remote is used as the pathname if provided)\n" + 062 "\t-e - use EPSV with IPv4 (default false)\n" + 063 "\t-E - encoding to use for control channel\n" + 064 "\t-f - issue FEAT command (remote and local files are ignored)\n" + 065 "\t-h - list hidden files (applies to -l and -n only)\n" + 066 "\t-k secs - use keep-alive timer (setControlKeepAliveTimeout)\n" + 067 "\t-l - list files using LIST (remote is used as the pathname if provided)\n" + 068 "\t Files are listed twice: first in raw mode, then as the formatted parsed data.\n" + 069 "\t N.B. if the wrong server-type is used, output may be lost. Use -U or -S as necessary.\n" + 070 "\t-L - use lenient future dates (server dates may be up to 1 day into future)\n" + 071 "\t-m - list file details using MDTM (remote is used as the pathname if provided)\n" + 072 "\t-n - list file names using NLST (remote is used as the pathname if provided)\n" + 073 "\t-p true|false|protocol[,true|false] - use FTPSClient with the specified protocol and/or isImplicit setting\n" + 074 "\t-s - store file on server (upload)\n" + 075 "\t-S - systemType set server system type (e.g. UNIX VMS WINDOWS)\n" + 076 "\t-t - list file details using MLST (remote is used as the pathname if provided)\n" + 077 "\t-U - save unparseable responses\n" + 078 "\t-w msec - wait time for keep-alive reply (setControlKeepAliveReplyTimeout)\n" + 079 "\t-T all|valid|none - use one of the built-in TrustManager implementations (none = JVM default)\n" + 080 "\t-y format - set default date format string\n" + 081 "\t-Y format - set recent date format string\n" + 082 "\t-Z timezone - set the server timezone for parsing LIST responses\n" + 083 "\t-z timezone - set the timezone for displaying MDTM, LIST, MLSD, MLST responses\n" + 084 "\t-PrH server[:port] - HTTP Proxy host and optional port[80] \n" + 085 "\t-PrU user - HTTP Proxy server username\n" + 086 "\t-PrP password - HTTP Proxy server password\n" + 087 "\t-# - add hash display during transfers\n"; 088 089 public static void main(String[] args) throws UnknownHostException 090 { 091 boolean storeFile = false, binaryTransfer = false, error = false, listFiles = false, listNames = false, hidden = false; 092 boolean localActive = false, useEpsvWithIPv4 = false, feat = false, printHash = false; 093 boolean mlst = false, mlsd = false, mdtm = false, saveUnparseable = false; 094 boolean lenient = false; 095 long keepAliveTimeout = -1; 096 int controlKeepAliveReplyTimeout = -1; 097 int minParams = 5; // listings require 3 params 098 String protocol = null; // SSL protocol 099 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 if (f != null) { 414 System.out.println(f.getRawListing()); 415 System.out.println(f.toFormattedString(displayTimeZoneId)); 416 } else { 417 System.out.println("File not found"); 418 } 419 } 420 if (mlst) { 421 FTPFile f = ftp.mlistFile(remote); 422 if (f != null){ 423 System.out.println(f.toFormattedString(displayTimeZoneId)); 424 } 425 } 426 if (listNames) { 427 for (String s : ftp.listNames(remote)) { 428 System.out.println(s); 429 } 430 } 431 // Do this last because it changes the client 432 if (listFiles) { 433 if (lenient || serverTimeZoneId != null) { 434 config.setLenientFutureDates(lenient); 435 if (serverTimeZoneId != null) { 436 config.setServerTimeZoneId(serverTimeZoneId); 437 } 438 ftp.configure(config ); 439 } 440 441 for (FTPFile f : ftp.listFiles(remote)) { 442 System.out.println(f.getRawListing()); 443 System.out.println(f.toFormattedString(displayTimeZoneId)); 444 } 445 } 446 } 447 else if (feat) 448 { 449 // boolean feature check 450 if (remote != null) { // See if the command is present 451 if (ftp.hasFeature(remote)) { 452 System.out.println("Has feature: "+remote); 453 } else { 454 if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) { 455 System.out.println("FEAT "+remote+" was not detected"); 456 } else { 457 System.out.println("Command failed: "+ftp.getReplyString()); 458 } 459 } 460 461 // Strings feature check 462 String []features = ftp.featureValues(remote); 463 if (features != null) { 464 for(String f : features) { 465 System.out.println("FEAT "+remote+"="+f+"."); 466 } 467 } else { 468 if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) { 469 System.out.println("FEAT "+remote+" is not present"); 470 } else { 471 System.out.println("Command failed: "+ftp.getReplyString()); 472 } 473 } 474 } else { 475 if (ftp.features()) { 476// Command listener has already printed the output 477 } else { 478 System.out.println("Failed: "+ftp.getReplyString()); 479 } 480 } 481 } 482 else if (doCommand != null) 483 { 484 if (ftp.doCommand(doCommand, remote)) { 485// Command listener has already printed the output 486// for(String s : ftp.getReplyStrings()) { 487// System.out.println(s); 488// } 489 } else { 490 System.out.println("Failed: "+ftp.getReplyString()); 491 } 492 } 493 else 494 { 495 OutputStream output; 496 497 output = new FileOutputStream(local); 498 499 ftp.retrieveFile(remote, output); 500 501 output.close(); 502 } 503 504 ftp.noop(); // check that control connection is working OK 505 506 ftp.logout(); 507 } 508 catch (FTPConnectionClosedException e) 509 { 510 error = true; 511 System.err.println("Server closed connection."); 512 e.printStackTrace(); 513 } 514 catch (IOException e) 515 { 516 error = true; 517 e.printStackTrace(); 518 } 519 finally 520 { 521 if (ftp.isConnected()) 522 { 523 try 524 { 525 ftp.disconnect(); 526 } 527 catch (IOException f) 528 { 529 // do nothing 530 } 531 } 532 } 533 534 System.exit(error ? 1 : 0); 535 } // end main 536 537 private static CopyStreamListener createListener(){ 538 return new CopyStreamListener(){ 539 private long megsTotal = 0; 540 541 @Override 542 public void bytesTransferred(CopyStreamEvent event) { 543 bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize()); 544 } 545 546 @Override 547 public void bytesTransferred(long totalBytesTransferred, 548 int bytesTransferred, long streamSize) { 549 long megs = totalBytesTransferred / 1000000; 550 for (long l = megsTotal; l < megs; l++) { 551 System.err.print("#"); 552 } 553 megsTotal = megs; 554 } 555 }; 556 } 557} 558