/plugins/FTP/tags/rel-0-7-3/com/fooware/net/FtpClient.java

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