/plugins/FTP/tags/release-0-9-7/com/fooware/net/FtpClient.java

# · Java · 1017 lines · 386 code · 106 blank · 525 comment · 64 complexity · 6230438498f7f26734ce193b263737c2 MD5 · raw file

  1. /*************************************************************************
  2. * Copyright (C) 1998, Chris Cheetham, fooware *
  3. * Distributed under the GNU General Public License *
  4. * http://www.fsf.org/copyleft/gpl.html *
  5. *************************************************************************/
  6. // Modified by Slava Pestov to use org.gjt.sp.util.Log for debugging.
  7. // Also modified by Slava Pestov to work on MacOS
  8. // (we now always print \r\n instead of using println(),
  9. // which sends a platform-specific line separator)
  10. //
  11. // Also modified by Vadim Voituk to add proxy support
  12. package com.fooware.net;
  13. import java.io.*;
  14. import java.net.ServerSocket;
  15. import java.net.Socket;
  16. import java.util.Enumeration;
  17. import java.util.Vector;
  18. import java.io.IOException;
  19. import java.net.UnknownHostException;
  20. import org.gjt.sp.util.Log;
  21. import com.fooware.net.proxy.Proxy;
  22. /**
  23. * Most of the method descriptions have been copied from RFC959, authors J.
  24. * Postel and J. Reynolds, 1985. The RFC can be viewed in its entirety at <A
  25. * HREF="http://sunsite.auc.dk/RFC/rfc/rfc959.html">http://sunsite.auc.dk/RFC/rfc/rfc959.html</A>.
  26. * <P>
  27. * Click <A HREF="ftp_snippets.html">here</A> to see some snippets that
  28. * demonstrate some the common methods.
  29. * <P>
  30. * Some have reported bugs when sending/receiving binary files via the
  31. * <CODE>FtpReader</CODE> and <CODE>FtpWriter</CODE>. To be safe, it is
  32. * recommended to use the analogous <CODE>FtpInputStream</CODE> and
  33. * <CODE>FtpOutputStream</CODE> methods. E.g., rather than <CODE>list()</CODE>,
  34. * use <CODE>listStream()</CODE>.
  35. *
  36. * @author <A HREF="mailto:cheetham@fooware.com">Chris Cheetham</A>
  37. * @version $Revision: 14855 $
  38. */
  39. public class FtpClient {
  40. public static final int TIMEOUT = 45000;
  41. //
  42. // interface
  43. //
  44. public FtpClient() {}
  45. public FtpClient(Proxy proxy) {
  46. this.proxy = proxy;
  47. }
  48. /**
  49. * Send the command string to the FTP server. Then get the response.
  50. */
  51. public void sendCommand(String command) throws IOException {
  52. String debugString = command;
  53. if (command.startsWith("PASS"))
  54. debugString = "PASS <password removed for security>";
  55. debug("sending command", debugString);
  56. out.write(command);
  57. out.write("\r\n");
  58. out.flush();
  59. setResponse();
  60. }
  61. /**
  62. * Return the last response received from the FTP server. The response are
  63. * stored in a collection, so repeatedly calling this method will return the
  64. * same response. New repsonses are added as requests are issued to the FTP
  65. * server and when data connections are closed.
  66. */
  67. public FtpResponse getResponse() {
  68. return response;
  69. }
  70. /**
  71. * Return an enumeration of all the responses received from the FTP server.
  72. */
  73. public Enumeration<FtpResponse> getAllResponses() {
  74. return responseArchive.elements();
  75. }
  76. /**
  77. * Connect to the server at the host on the default FTP port.
  78. */
  79. public void connect(String hostName) throws IOException {
  80. connect(hostName, DEFAULT_PORT);
  81. }
  82. /**
  83. * Connect to the server at the host on the port.
  84. */
  85. public void connect(String hostName, int port) throws IOException {
  86. if (proxy != null) {
  87. cmdSocket = proxy.openSocket(hostName, port);
  88. } else {
  89. cmdSocket = new Socket(hostName, port);
  90. }
  91. cmdSocket.setSoTimeout(TIMEOUT);
  92. in = new BufferedReader(new InputStreamReader(cmdSocket.getInputStream()));
  93. out = new BufferedWriter(new OutputStreamWriter(cmdSocket.getOutputStream()));
  94. setResponse();
  95. }
  96. /**
  97. * USER NAME (USER) <BR>
  98. * The argument field is a Telnet string identifying the user. The user
  99. * identification is that which is required by the server for access to its
  100. * file system. This command will normally be the first command transmitted
  101. * by the user after the control connections are made (some servers may
  102. * require this). Additional identification information in the form of a
  103. * password and/or an account command may also be required by some servers.
  104. * Servers may allow a new USER command to be entered at any point in order
  105. * to change the access control and/or accounting information. This has the
  106. * effect of flushing any user, password, and account information already
  107. * supplied and beginning the login sequence again. All transfer parameters
  108. * are unchanged and any file transfer in progress is completed under the
  109. * old access control parameters. <BR>
  110. * <I>Per RFC959</I>
  111. */
  112. public void userName(String userName) throws IOException {
  113. sendCommand("USER " + userName);
  114. }
  115. /**
  116. * PASSWORD (PASS) <BR>
  117. * The argument field is a Telnet string specifying the user's password.
  118. * This command must be immediately preceded by the user name command, and,
  119. * for some sites, completes the user's identification for access control.
  120. * Since password information is quite sensitive, it is desirable in general
  121. * to "mask" it or suppress typeout. It appears that the server has no
  122. * foolproof way to achieve this. It is therefore the responsibility of the
  123. * user-FTP process to hide the sensitive password information. <BR>
  124. * <I>Per RFC959</I>
  125. */
  126. public void password(String password) throws IOException {
  127. sendCommand("PASS " + password);
  128. }
  129. /**
  130. * ACCOUNT (ACCT) <BR>
  131. * The argument field is a Telnet string identifying the user's account. The
  132. * command is not necessarily related to the USER command, as some sites may
  133. * require an account for login and others only for specific access, such as
  134. * storing files. In the latter case the command may arrive at any time.
  135. * There are reply codes to differentiate these cases for the automation:
  136. * when account information is required for login, the response to a
  137. * successful PASSword command is reply code 332. On the other hand, if
  138. * account information is NOT required for login, the reply to a successful
  139. * PASSword command is 230; and if the account information is needed for a
  140. * command issued later in the dialogue, the server should return a 332 or
  141. * 532 reply depending on whether it stores (pending receipt of the ACCounT
  142. * command) or discards the command, respectively. <BR>
  143. * <I>Per RFC959</I>
  144. */
  145. public void account(String account) throws IOException {
  146. sendCommand("ACCT " + account);
  147. }
  148. /**
  149. * CHANGE WORKING DIRECTORY (CWD) <BR>
  150. * This command allows the user to work with a different directory or
  151. * dataset for file storage or retrieval without altering his login or
  152. * accounting information. Transfer parameters are similarly unchanged. The
  153. * argument is a pathname specifying a directory or other system dependent
  154. * file group designator. <BR>
  155. * <I>Per RFC959</I>
  156. */
  157. public void changeWorkingDirectory(String path) throws IOException {
  158. sendCommand("CWD " + path);
  159. }
  160. /**
  161. * CHANGE TO PARENT DIRECTORY (CDUP) <BR>
  162. * This command is a special case of CWD, and is included to simplify the
  163. * implementation of programs for transferring directory trees between
  164. * operating systems having different syntaxes for naming the parent
  165. * directory. The reply codes shall be identical to the reply codes of CWD.
  166. * <BR>
  167. * <I>Per RFC959</I>
  168. */
  169. public void changeToParentDirectory() throws IOException {
  170. sendCommand("CDUP");
  171. }
  172. /**
  173. * STRUCTURE MOUNT (SMNT) This command allows the user to mount a different
  174. * file system data structure without altering his login or accounting
  175. * information. Transfer parameters are similarly unchanged. The argument is
  176. * a pathname specifying a directory or other system dependent file group
  177. * designator. <BR>
  178. * <I>Per RFC959</I>
  179. */
  180. public void structureMount(String path) throws IOException {
  181. sendCommand("SMNT " + path);
  182. }
  183. /**
  184. * REINITIALIZE (REIN) <BR>
  185. * This command terminates a USER, flushing all I/O and account information,
  186. * except to allow any transfer in progress to be completed. All parameters
  187. * are reset to the default settings and the control connection is left
  188. * open. This is identical to the state in which a user finds himself
  189. * immediately after the control connection is opened. A USER command may be
  190. * expected to follow. <BR>
  191. * <I>Per RFC959</I>
  192. */
  193. public void reinitialize() throws IOException {
  194. sendCommand("REIN");
  195. }
  196. /**
  197. * LOGOUT (QUIT) <BR>
  198. * This command terminates a USER and if file transfer is not in progress,
  199. * the server closes the control connection. If file transfer is in
  200. * progress, the connection will remain open for result response and the
  201. * server will then close it. If the user-process is transferring files for
  202. * several USERs but does not wish to close and then reopen connections for
  203. * each, then the REIN command should be used instead of QUIT. <BR>
  204. * An unexpected close on the control connection will cause the server to
  205. * take the effective action of an abort (ABOR) and a logout (QUIT). <BR>
  206. * <I>Per RFC959</I>
  207. */
  208. public void logout() throws IOException {
  209. sendCommand("QUIT");
  210. }
  211. /**
  212. * DATA PORT (PORT) <BR>
  213. * The argument is a HOST-PORT specification for the data port to be used in
  214. * data connection. There are defaults for both the user and server data
  215. * ports, and under normal circumstances this command and its reply are not
  216. * needed. If this command is used, the argument is the concatenation of a
  217. * 32-bit internet host address and a 16-bit TCP port address. This address
  218. * information is broken into 8-bit fields and the value of each field is
  219. * transmitted as a decimal number (in character string representation). The
  220. * fields are separated by commas. A port command would be: <BR>
  221. * PORT h1,h2,h3,h4,p1,p2 <BR>
  222. * where h1 is the high order 8 bits of the internet host address. <BR>
  223. * <I>Per RFC959</I><BR>
  224. * <B>Note:</B> The preceeding excerpt is provided for informational
  225. * purposes. For *this* ftp client, you must issue at least one dataPort()
  226. * command is you plan to do any ftp processing that uses the data
  227. * connection rather than the command connect, e.g. retrieve. Per the RFC,
  228. * there is a default user port number, but I have yet to find the port
  229. * number. It is not necessary to do more than one.<BR>
  230. */
  231. public void dataPort() throws IOException, UnknownHostException {
  232. StringBuilder command = new StringBuilder("PORT ");
  233. String host = cmdSocket.getLocalAddress().getHostAddress();
  234. command.append(host.replace('.', ','));
  235. if (dataSocket != null) {
  236. dataSocket.close();
  237. }
  238. dataSocket = new ServerSocket(0);
  239. dataSocket.setSoTimeout(TIMEOUT);
  240. int port = dataSocket.getLocalPort();
  241. command.append(',');
  242. command.append(port / 256);
  243. command.append(',');
  244. command.append(port % 256);
  245. sendCommand(command.toString());
  246. }
  247. /**
  248. * PASSIVE (PASV) <BR>
  249. * This command requests the server-DTP to "listen" on a data port (which is
  250. * not its default data port) and to wait for a connection rather than
  251. * initiate one upon receipt of a transfer command. The response to this
  252. * command includes the host and port address this server is listening on.
  253. * <BR>
  254. * <I>Per RFC959</I><BR>
  255. */
  256. public void passive() throws IOException {
  257. sendCommand("PASV");
  258. FtpResponse resp = getResponse();
  259. if (!resp.isPositiveCompletion()) {
  260. Log.log(Log.ERROR, this, Thread.currentThread()
  261. + ": Couldn't set passive, trying data port");
  262. dataPort();
  263. return;
  264. }
  265. try {
  266. String message = resp.getMessage();
  267. int bound_r = message.lastIndexOf(')');
  268. int bound_l = message.lastIndexOf('(', bound_r - 1) + 1;
  269. String remoteAddr = message.substring(bound_l, bound_r);
  270. int comma1 = remoteAddr.lastIndexOf(',');
  271. int port = Integer.parseInt(remoteAddr.substring(comma1 + 1));
  272. int comma2 = remoteAddr.lastIndexOf(',', comma1 - 1);
  273. port |= Integer.parseInt(remoteAddr.substring(comma2 + 1, comma1)) << 8;
  274. remoteAddr = remoteAddr.substring(0, comma2).replace(',', '.');
  275. if (proxy != null)
  276. passiveSocket = proxy.openSocket(remoteAddr, port);
  277. else
  278. passiveSocket = new Socket(remoteAddr, port);
  279. passiveSocket.setSoTimeout(TIMEOUT);
  280. } catch (StringIndexOutOfBoundsException e) {
  281. Log.log(Log.ERROR, this, Thread.currentThread() + ": Couldn't set passive, trying data port");
  282. dataPort();
  283. return;
  284. }
  285. }
  286. /**
  287. * REPRESENTATION TYPE (TYPE) <BR>
  288. * The argument specifies the representation type as described in the
  289. * Section on Data Representation and Storage. Several types take a second
  290. * parameter. The first parameter is denoted by a single Telnet character,
  291. * as is the second Format parameter for ASCII and EBCDIC; the second
  292. * parameter for local byte is a decimal integer to indicate Bytesize. The
  293. * parameters are separated by a <SP> (Space, ASCII code 32). The following
  294. * codes are assigned for type: <BR>
  295. * <CODE><PRE>
  296. * \ /
  297. * A - ASCII | | N - Non-print
  298. * |-&gt;&lt;-| T - Telnet format effectors
  299. * E - EBCDIC| | C - Carriage Control (ASA)
  300. * / \
  301. * I - Image
  302. * L &lt;byte size&gt; - Local byte Byte size
  303. * </PRE></CODE> <BR>
  304. * The default representation type is ASCII Non-print. If the Format
  305. * parameter is changed, and later just the first argument is changed,
  306. * Format then returns to the Non-print default. <BR>
  307. * <I>Per RFC959</I><BR>
  308. * For convenience, the following constants can be used: <TABLE>
  309. * <TR>
  310. * <TD>
  311. * <UL>
  312. * <LI>ASCII_TYPE</LI>
  313. * <LI>EBCDIC_TYPE</LI>
  314. * <LI>IMAGE_TYPE</LI>
  315. * </UL>
  316. * </TD>
  317. * <TD>
  318. * <UL>
  319. * <LI>NON_PRINT_FORMAT</LI>
  320. * <LI>TELNET_EFFECTORS_FORMAT</LI>
  321. * <LI>CARRIAGE_CONTROL_FORMAT</LI>
  322. * </UL>
  323. * </TD>
  324. * </TR>
  325. * </TABLE>
  326. */
  327. public void representationType(char type, char format) throws IOException {
  328. if (type == IMAGE_TYPE) {
  329. sendCommand("TYPE " + type);
  330. } else {
  331. sendCommand("TYPE " + type + ' ' + format);
  332. }
  333. }
  334. /**
  335. * @see #representationType(char, char)
  336. */
  337. public void representationType(char type) throws IOException {
  338. representationType(type, NON_PRINT_FORMAT);
  339. }
  340. /**
  341. * Special case of specifying the local byte size.
  342. */
  343. public void representationType(int size) throws IOException {
  344. sendCommand("TYPE L " + size);
  345. }
  346. /**
  347. * FILE STRUCTURE (STRU) <BR>
  348. * The argument is a single Telnet character code specifying file structure
  349. * described in the Section on Data Representation and Storage. The
  350. * following codes are assigned for structure: <BR>
  351. * F - File (no record structure) <BR>
  352. * R - Record structure <BR>
  353. * P - Page structure <BR>
  354. * The default structure is File. <BR>
  355. * <I>Per RFC959</I><BR>
  356. * For convenience, the following constants can be used: <TABLE>
  357. * <TR>
  358. * <TD>
  359. * <UL>
  360. * <LI>FILE_STRUCTURE</LI>
  361. * <LI>RECORD_STRUCTURE</LI>
  362. * <LI>PAGE_STRUCTURE</LI>
  363. * </UL>
  364. * </TD>
  365. * </TR>
  366. * </TABLE>
  367. */
  368. public void structure(char structure) throws IOException {
  369. sendCommand("STRU " + structure);
  370. }
  371. /**
  372. * TRANSFER MODE (MODE) <BR>
  373. * The argument is a single Telnet character code specifying the data
  374. * transfer modes described in the Section on Transmission Modes. The
  375. * following codes are assigned for transfer modes: <BR>
  376. * <CODE><PRE>
  377. * S - Stream
  378. * B - Block
  379. * C - Compressed
  380. * </PRE></CODE> The default transfer mode is Stream. <BR>
  381. * <I>Per RFC959</I><BR>
  382. * For convenience, the following constants can be used: <TABLE>
  383. * <TR>
  384. * <TD>
  385. * <UL>
  386. * <LI>STREAM_MODE</LI>
  387. * <LI>BLOCK_MODE</LI>
  388. * <LI>COMPRESSED_MODE</LI>
  389. * </UL>
  390. * </TD>
  391. * </TR>
  392. * </TABLE>
  393. */
  394. public void transferMode(char mode) throws IOException {
  395. sendCommand("MODE " + mode);
  396. }
  397. /**
  398. * RETRIEVE (RETR) <BR>
  399. * This command causes the server-DTP to transfer a copy of the file,
  400. * specified in the pathname, to the server- or user-DTP at the other end of
  401. * the data connection. The status and contents of the file at the server
  402. * site shall be unaffected. <BR>
  403. * <I>Per RFC959</I> <BR>
  404. * <B>Note:</B> It is important that the reader be closed after it is done
  405. * being processed. This signals the ftp client to get the next response
  406. * from the server.
  407. *
  408. * @return a reader from which can be read the retrieved file data
  409. */
  410. public FtpReader retrieve(String path) throws IOException {
  411. InputStream istr = getRetrieveStream(path);
  412. if (istr == null)
  413. return null;
  414. InputStreamReader in = new InputStreamReader(istr);
  415. return new FtpReader(in, this);
  416. }
  417. public FtpInputStream retrieveStream(String path) throws IOException {
  418. InputStream istr = getRetrieveStream(path);
  419. if (istr == null)
  420. return null;
  421. return new FtpInputStream(istr, this);
  422. }
  423. protected InputStream getRetrieveStream(String path) throws IOException {
  424. sendCommand("RETR " + path);
  425. if (!getResponse().isPositivePreliminary()) {
  426. return null;
  427. }
  428. return getTransferSocket().getInputStream();
  429. }
  430. /**
  431. * STORE (STOR) <BR>
  432. * This command causes the server-DTP to accept the data transferred via the
  433. * data connection and to store the data as a file at the server site. If
  434. * the file specified in the pathname exists at the server site, then its
  435. * contents shall be replaced by the data being transferred. A new file is
  436. * created at the server site if the file specified in the pathname does not
  437. * already exist. <BR>
  438. * <I>Per RFC959</I> <BR>
  439. * <B>Note:</B> It is important that the writer be closed after it is done
  440. * being processed. This signals the ftp client to get the next response
  441. * from the server.
  442. *
  443. * @return a writer into which can be written the data for the host file
  444. */
  445. public FtpWriter store(String path) throws IOException {
  446. OutputStream ostr = getStoreStream(path);
  447. if (ostr == null)
  448. return null;
  449. OutputStreamWriter out = new OutputStreamWriter(ostr);
  450. return new FtpWriter(out, this);
  451. }
  452. public FtpOutputStream storeStream(String path) throws IOException {
  453. OutputStream ostr = getStoreStream(path);
  454. if (ostr == null)
  455. return null;
  456. return new FtpOutputStream(ostr, this);
  457. }
  458. protected OutputStream getStoreStream(String path) throws IOException {
  459. sendCommand("STOR " + path);
  460. if (!getResponse().isPositivePreliminary()) {
  461. return null;
  462. }
  463. return getTransferSocket().getOutputStream();
  464. }
  465. /**
  466. * STORE UNIQUE (STOU) <BR>
  467. * This command behaves like STOR except that the resultant file is to be
  468. * created in the current directory under a name unique to that directory.
  469. * The 250 Transfer Started response must include the name generated. <BR>
  470. * <I>Per RFC959</I> <BR>
  471. * <B>Note:</B> It is important that the writer be closed after it is done
  472. * being processed. This signals the ftp client to get the next response
  473. * from the server.
  474. *
  475. * @return a writer into which can be written the data for the host file
  476. */
  477. public FtpWriter storeUnique() throws IOException {
  478. OutputStream ostr = getStoreUniqueStream();
  479. if (ostr == null)
  480. return null;
  481. OutputStreamWriter out = new OutputStreamWriter(ostr);
  482. return new FtpWriter(out, this);
  483. }
  484. public FtpOutputStream storeUniqueStream() throws IOException {
  485. OutputStream ostr = getStoreUniqueStream();
  486. if (ostr == null)
  487. return null;
  488. return new FtpOutputStream(ostr, this);
  489. }
  490. protected OutputStream getStoreUniqueStream() throws IOException {
  491. sendCommand("STOU");
  492. if (!getResponse().isPositivePreliminary()) {
  493. return null;
  494. }
  495. return getTransferSocket().getOutputStream();
  496. }
  497. /**
  498. * APPEND (with create) (APPE) <BR>
  499. * This command causes the server-DTP to accept the data transferred via the
  500. * data connection and to store the data in a file at the server site. If
  501. * the file specified in the pathname exists at the server site, then the
  502. * data shall be appended to that file; otherwise the file specified in the
  503. * pathname shall be created at the server site. <BR>
  504. * <I>Per RFC959</I> <BR>
  505. * <B>Note:</B> It is important that the writer be closed after it is done
  506. * being processed. This signals the ftp client to get the next response
  507. * from the server.
  508. *
  509. * @return a writer into which can be written the data for the host file
  510. */
  511. public FtpWriter append(String path) throws IOException {
  512. OutputStream ostr = getAppendStream(path);
  513. if (ostr == null)
  514. return null;
  515. OutputStreamWriter out = new OutputStreamWriter(ostr);
  516. return new FtpWriter(out, this);
  517. }
  518. public FtpOutputStream appendStream(String path) throws IOException {
  519. OutputStream ostr = getAppendStream(path);
  520. if (ostr == null)
  521. return null;
  522. return new FtpOutputStream(ostr, this);
  523. }
  524. protected OutputStream getAppendStream(String path) throws IOException {
  525. sendCommand("APPE " + path);
  526. if (!getResponse().isPositivePreliminary()) {
  527. return null;
  528. }
  529. return getTransferSocket().getOutputStream();
  530. }
  531. /**
  532. * ALLOCATE (ALLO) <BR>
  533. * This command may be required by some servers to reserve sufficient
  534. * storage to accommodate the new file to be transferred. The argument shall
  535. * be a decimal integer representing the number of bytes (using the logical
  536. * byte size) of storage to be reserved for the file. For files sent with
  537. * record or page structure a maximum record or page size (in logical bytes)
  538. * might also be necessary; this is indicated by a decimal integer in a
  539. * second argument field of the command. This second argument is optional,
  540. * but when present should be separated from the first by the three Telnet
  541. * characters [SP] R [SP]. This command shall be followed by a STORe or
  542. * APPEnd command. The ALLO command should be treated as a NOOP (no
  543. * operation) by those servers which do not require that the maximum size of
  544. * the file be declared beforehand, and those servers interested in only the
  545. * maximum record or page size should accept a dummy value in the first
  546. * argument and ignore it. <BR>
  547. * <I>Per RFC959</I>
  548. */
  549. public void allocate(int size, int recSize) throws IOException {
  550. sendCommand("ALLO " + size + " R " + recSize);
  551. }
  552. /**
  553. * @see #allocate(int, int)
  554. */
  555. public void allocate(int size) throws IOException {
  556. sendCommand("ALLO " + size);
  557. }
  558. /**
  559. * RESTART (REST) <BR>
  560. * The argument field represents the server marker at which file transfer is
  561. * to be restarted. This command does not cause file transfer but skips over
  562. * the file to the specified data checkpoint. This command shall be
  563. * immediately followed by the appropriate FTP service command which shall
  564. * cause file transfer to resume. <BR>
  565. * <I>Per RFC959</I>
  566. */
  567. public void restart(String marker) throws IOException {
  568. sendCommand("REST " + marker);
  569. }
  570. /**
  571. * RENAME FROM (RNFR) <BR>
  572. * This command specifies the old pathname of the file which is to be
  573. * renamed. This command must be immediately followed by a "rename to"
  574. * command specifying the new file pathname. <BR>
  575. * <I>Per RFC959</I>
  576. *
  577. * @see #renameTo(String)
  578. */
  579. public void renameFrom(String path) throws IOException {
  580. sendCommand("RNFR " + path);
  581. }
  582. /**
  583. * RENAME TO (RNTO) <BR>
  584. * This command specifies the new pathname of the file specified in the
  585. * immediately preceding "rename from" command. Together the two commands
  586. * cause a file to be renamed. <BR>
  587. * <I>Per RFC959</I>
  588. *
  589. * @see #renameFrom(String)
  590. */
  591. public void renameTo(String path) throws IOException {
  592. sendCommand("RNTO " + path);
  593. }
  594. /**
  595. * ABORT (ABOR) <BR>
  596. * This command tells the server to abort the previous FTP service command
  597. * and any associated transfer of data. The abort command may require
  598. * "special action", as discussed in the Section on FTP Commands, to force
  599. * recognition by the server. No action is to be taken if the previous
  600. * command has been completed (including data transfer). The control
  601. * connection is not to be closed by the server, but the data connection
  602. * must be closed. <BR>
  603. * There are two cases for the server upon receipt of this command: (1) the
  604. * FTP service command was already completed, or (2) the FTP service command
  605. * is still in progress. In the first case, the server closes the data
  606. * connection (if it is open) and responds with a 226 reply, indicating that
  607. * the abort command was successfully processed. <BR>
  608. * In the second case, the server aborts the FTP service in progress and
  609. * closes the data connection, returning a 426 reply to indicate that the
  610. * service request terminated abnormally. The server then sends a 226 reply,
  611. * indicating that the abort command was successfully processed. <BR>
  612. * <I>Per RFC959</I>
  613. */
  614. public void abort() throws IOException {
  615. sendCommand("ABOR");
  616. }
  617. /**
  618. * DELETE (DELE) This command causes the file specified in the pathname to
  619. * be deleted at the server site. If an extra level of protection is desired
  620. * (such as the query, "Do you really wish to delete?"), it should be
  621. * provided by the user-FTP process. <BR>
  622. * <I>Per RFC959</I>
  623. */
  624. public void delete(String path) throws IOException {
  625. sendCommand("DELE " + path);
  626. }
  627. /**
  628. * REMOVE DIRECTORY (RMD) <BR>
  629. * This command causes the directory specified in the pathname to be removed
  630. * as a directory (if the pathname is absolute) or as a subdirectory of the
  631. * current working directory (if the pathname is relative). <BR>
  632. * <I>Per RFC959</I>
  633. */
  634. public void removeDirectory(String path) throws IOException {
  635. sendCommand("RMD " + path);
  636. }
  637. /**
  638. * MAKE DIRECTORY (MKD) <BR>
  639. * This command causes the directory specified in the pathname to be created
  640. * as a directory (if the pathname is absolute) or as a subdirectory of the
  641. * current working directory (if the pathname is relative). <BR>
  642. * <I>Per RFC959</I>
  643. */
  644. public void makeDirectory(String path) throws IOException {
  645. sendCommand("MKD " + path);
  646. }
  647. /**
  648. * PRINT WORKING DIRECTORY (PWD) <BR>
  649. * This command causes the name of the current working directory to be
  650. * returned in the reply. <BR>
  651. * <I>Per RFC959</I>
  652. */
  653. public void printWorkingDirectory() throws IOException {
  654. sendCommand("PWD");
  655. }
  656. /**
  657. * LIST (LIST) <BR>
  658. * This command causes a list to be sent from the server to the passive DTP.
  659. * If the pathname specifies a directory or other group of files, the server
  660. * should transfer a list of files in the specified directory. If the
  661. * pathname specifies a file then the server should send current information
  662. * on the file. A null argument implies the user's current working or
  663. * default directory. The data transfer is over the data connection in type
  664. * ASCII or type EBCDIC. (The user must ensure that the TYPE is
  665. * appropriately ASCII or EBCDIC). Since the information on a file may vary
  666. * widely from system to system, this information may be hard to use
  667. * automatically in a program, but may be quite useful to a human user. <BR>
  668. * <I>Per RFC959</I> <BR>
  669. * <B>Note:</B> It is important that the reader be closed after it is done
  670. * being processed. This signals the ftp client to get the next response
  671. * from the server.
  672. *
  673. * @return a reader from which can be read the retrieved file data
  674. */
  675. public FtpReader list(String path) throws IOException {
  676. InputStream istr = getListStream(path);
  677. if (istr == null)
  678. return null;
  679. InputStreamReader in = new InputStreamReader(istr);
  680. return new FtpReader(in, this);
  681. }
  682. /**
  683. * @see #list(String)
  684. */
  685. public FtpReader list() throws IOException {
  686. return list(null);
  687. }
  688. public FtpInputStream listStream(String path) throws IOException {
  689. InputStream istr = getListStream(path);
  690. if (istr == null)
  691. return null;
  692. return new FtpInputStream(istr, this);
  693. }
  694. public FtpInputStream listStream() throws IOException {
  695. return listStream(null);
  696. }
  697. protected InputStream getListStream(String path) throws IOException {
  698. if (path == null) {
  699. sendCommand("LIST");
  700. } else {
  701. sendCommand("LIST " + path);
  702. }
  703. if (!getResponse().isPositivePreliminary()) {
  704. return null;
  705. }
  706. return getTransferSocket().getInputStream();
  707. }
  708. /**
  709. * NAME LIST (NLST) This command causes a directory listing to be sent from
  710. * server to user site. The pathname should specify a directory or other
  711. * system-specific file group descriptor; a null argument implies the
  712. * current directory. The server will return a stream of names of files and
  713. * no other information. The data will be transferred in ASCII or EBCDIC
  714. * type over the data connection as valid pathname strings separated by
  715. * <CRLF> or
  716. * <NL>. (Again the user must ensure that the TYPE is correct.) This
  717. * command is intended to return information that can be used by a program
  718. * to further process the files automatically. For example, in the
  719. * implementation of a "multiple get" function. <BR>
  720. * <I>Per RFC959</I> <BR>
  721. * <B>Note:</B> It is important that the reader be closed after it is done
  722. * being processed. This signals the ftp client to get the next response
  723. * from the server.
  724. *
  725. * @return a reader from which can be read the retrieved file data
  726. */
  727. public FtpReader nameList(String path) throws IOException {
  728. InputStream istr = getNameListStream(path);
  729. if (istr == null)
  730. return null;
  731. InputStreamReader in = new InputStreamReader(istr);
  732. return new FtpReader(in, this);
  733. }
  734. /**
  735. * @see #nameList(String)
  736. */
  737. public FtpReader nameList() throws IOException {
  738. return nameList(null);
  739. }
  740. public FtpInputStream nameListStream(String path) throws IOException {
  741. InputStream istr = getNameListStream(path);
  742. if (istr == null)
  743. return null;
  744. return new FtpInputStream(istr, this);
  745. }
  746. public FtpInputStream nameListStream() throws IOException {
  747. return nameListStream(null);
  748. }
  749. protected InputStream getNameListStream(String path) throws IOException {
  750. if (path == null) {
  751. sendCommand("NLIST");
  752. } else {
  753. sendCommand("NLST " + path);
  754. }
  755. if (!getResponse().isPositivePreliminary()) {
  756. return null;
  757. }
  758. return getTransferSocket().getInputStream();
  759. }
  760. /**
  761. * SITE PARAMETERS (SITE) <BR>
  762. * This command is used by the server to provide services specific to his
  763. * system that are essential to file transfer but not sufficiently universal
  764. * to be included as commands in the protocol. The nature of these services
  765. * and the specification of their syntax can be stated in a reply to the
  766. * HELP SITE command. <BR>
  767. * <I>Per RFC959</I>
  768. */
  769. public void siteParameters(String param) throws IOException {
  770. sendCommand("SITE " + param);
  771. }
  772. /**
  773. * SYSTEM (SYST) <BR>
  774. * This command is used to find out the type of operating system at the
  775. * server. The reply shall have as its first word one of the system names
  776. * listed in the current version of the Assigned Numbers document [4]. <BR>
  777. * <I>Per RFC959</I>
  778. */
  779. public void system() throws IOException {
  780. sendCommand("SYST");
  781. }
  782. /**
  783. * STATUS (STAT) <BR>
  784. * This command shall cause a status response to be sent over the control
  785. * connection in the form of a reply. The command may be sent during a file
  786. * transfer (along with the Telnet IP and Synch signals--see the Section on
  787. * FTP Commands) in which case the server will respond with the status of
  788. * the operation in progress, or it may be sent between file transfers. In
  789. * the latter case, the command may have an argument field. If the argument
  790. * is a pathname, the command is analogous to the "list" command except that
  791. * data shall be transferred over the control connection. If a partial
  792. * pathname is given, the server may respond with a list of file names or
  793. * attributes associated with that specification. If no argument is given,
  794. * the server should return general status information about the server FTP
  795. * process. This should include current values of all transfer parameters
  796. * and the status of connections. <BR>
  797. * <I>Per RFC959</I>
  798. */
  799. public void status(String path) throws IOException {
  800. if (path == null) {
  801. sendCommand("STAT");
  802. } else {
  803. sendCommand("STAT " + path);
  804. }
  805. }
  806. /**
  807. * @see #status(String)
  808. */
  809. public void status() throws IOException {
  810. status(null);
  811. }
  812. /**
  813. * HELP (HELP) <BR>
  814. * This command shall cause the server to send helpful information regarding
  815. * its implementation status over the control connection to the user. The
  816. * command may take an argument (e.g., any command name) and return more
  817. * specific information as a response. The reply is type 211 or 214. It is
  818. * suggested that HELP be allowed before entering a USER command. The server
  819. * may use this reply to specify site-dependent parameters, e.g., in
  820. * response to HELP SITE. <BR>
  821. * <I>Per RFC959</I>
  822. */
  823. public void help(String arg) throws IOException {
  824. if (arg == null) {
  825. sendCommand("HELP");
  826. } else {
  827. sendCommand("HELP " + arg);
  828. }
  829. }
  830. /**
  831. * @see #help(String)
  832. */
  833. public void help() throws IOException {
  834. help(null);
  835. }
  836. /**
  837. * NOOP (NOOP) <BR>
  838. * This command does not affect any parameters or previously entered
  839. * commands. It specifies no action other than that the server send an OK
  840. * reply. <BR>
  841. * <I>Per RFC959</I>
  842. */
  843. public void noOp() throws IOException {
  844. sendCommand("NOOP");
  845. }
  846. public static final int DEFAULT_PORT = 21;
  847. public static final char ASCII_TYPE = 'A';
  848. public static final char IMAGE_TYPE = 'I';
  849. public static final char EBCDIC_TYPE = 'E';
  850. public static final char LOCAL_FORMAT = 'L';
  851. public static final char NON_PRINT_FORMAT = 'N';
  852. public static final char TELNET_EFFECTORS_FORMAT = 'T';
  853. public static final char CARRIAGE_CONTROL_FORMAT = 'C';
  854. public static final char FILE_STRUCTURE = 'F';
  855. public static final char RECORD_STRUCTURE = 'R';
  856. public static final char PAGE_STRUCTURE = 'P';
  857. public static final char STREAM_MODE = 'S';
  858. public static final char BLOCK_MODE = 'B';
  859. public static final char COMPRESSED_MODE = 'C';
  860. //
  861. // framework
  862. //
  863. /**
  864. * Set the current response. Also, add the response to the archive.
  865. */
  866. protected void setResponse() throws IOException {
  867. response = new FtpResponse(in);
  868. responseArchive.addElement(response);
  869. debug("received response", response);
  870. }
  871. /**
  872. * Called by the FtpReader and FtpWriter classes when they are explicitly
  873. * closed.
  874. */
  875. protected void closeTransferSocket() throws IOException {
  876. if (dataXfrSocket != null) {
  877. dataXfrSocket.close();
  878. dataXfrSocket = null;
  879. setResponse();
  880. }
  881. }
  882. //
  883. // implementation
  884. //
  885. private void debug(Object heading, Object message) {
  886. Log.log(Log.DEBUG, this, Thread.currentThread() + ": " + heading + ": "+ message);
  887. }
  888. private Socket getTransferSocket() throws IOException {
  889. if (dataXfrSocket != null) {
  890. dataXfrSocket.close();
  891. dataXfrSocket = null;
  892. }
  893. if (passiveSocket != null) {
  894. dataXfrSocket = passiveSocket;
  895. } else if (dataSocket != null) {
  896. dataXfrSocket = dataSocket.accept();
  897. dataXfrSocket.setSoTimeout(TIMEOUT);
  898. }
  899. return dataXfrSocket;
  900. }
  901. //private boolean useReaderWriter; // temporary commented as useless (voituk)
  902. private BufferedReader in;
  903. private BufferedWriter out;
  904. private Socket cmdSocket;
  905. private ServerSocket dataSocket;
  906. private Socket dataXfrSocket;
  907. private Socket passiveSocket;
  908. private FtpResponse response;
  909. private Vector<FtpResponse> responseArchive = new Vector<FtpResponse>();
  910. private Proxy proxy;
  911. }