/plugins/FTP/tags/release-0-2-1-again/com/fooware/net/FtpClient.java

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