From 063284837c8c366e5502b1b0264b8eb807b61732 Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 14:21:09 +0100 Subject: Basic upload functionality to predifined location, with basic file browser --- AndroidManifest.xml | 26 + README | 5 + bin/blauploader.apk | Bin 0 -> 59814 bytes bin/classes.dex | Bin 0 -> 102612 bytes bin/com/lc8n/blauploader/FileBrowser$1.class | Bin 0 -> 1914 bytes bin/com/lc8n/blauploader/FileBrowser.class | Bin 0 -> 4189 bytes bin/com/lc8n/blauploader/FileUpload.class | Bin 0 -> 2063 bytes bin/com/lc8n/blauploader/ProgressInputStream.class | Bin 0 -> 2124 bytes bin/com/lc8n/blauploader/R$attr.class | Bin 0 -> 346 bytes bin/com/lc8n/blauploader/R$drawable.class | Bin 0 -> 406 bytes bin/com/lc8n/blauploader/R$id.class | Bin 0 -> 397 bytes bin/com/lc8n/blauploader/R$layout.class | Bin 0 -> 431 bytes bin/com/lc8n/blauploader/R$string.class | Bin 0 -> 433 bytes bin/com/lc8n/blauploader/R.class | Bin 0 -> 545 bytes .../apache/commons/net/DatagramSocketClient.class | Bin 0 -> 2475 bytes .../apache/commons/net/DatagramSocketFactory.class | Bin 0 -> 380 bytes .../commons/net/DefaultDatagramSocketFactory.class | Bin 0 -> 976 bytes .../apache/commons/net/DefaultSocketFactory.class | Bin 0 -> 1934 bytes .../net/MalformedServerReplyException.class | Bin 0 -> 506 bytes .../apache/commons/net/PrintCommandListener.class | Bin 0 -> 1016 bytes .../apache/commons/net/ProtocolCommandEvent.class | Bin 0 -> 1296 bytes .../commons/net/ProtocolCommandListener.class | Bin 0 -> 294 bytes .../commons/net/ProtocolCommandSupport.class | Bin 0 -> 2226 bytes bin/org/apache/commons/net/SocketClient.class | Bin 0 -> 5762 bytes bin/org/apache/commons/net/ftp/Configurable.class | Bin 0 -> 202 bytes bin/org/apache/commons/net/ftp/FTP.class | Bin 0 -> 12068 bytes bin/org/apache/commons/net/ftp/FTPClient.class | Bin 0 -> 19032 bytes .../apache/commons/net/ftp/FTPClientConfig.class | Bin 0 -> 5286 bytes bin/org/apache/commons/net/ftp/FTPCommand.class | Bin 0 -> 2776 bytes .../net/ftp/FTPConnectionClosedException.class | Bin 0 -> 511 bytes bin/org/apache/commons/net/ftp/FTPFile.class | Bin 0 -> 3444 bytes .../commons/net/ftp/FTPFileEntryParser.class | Bin 0 -> 499 bytes .../commons/net/ftp/FTPFileEntryParserImpl.class | Bin 0 -> 1496 bytes .../commons/net/ftp/FTPListParseEngine.class | Bin 0 -> 3788 bytes bin/org/apache/commons/net/ftp/FTPReply.class | Bin 0 -> 4278 bytes bin/org/apache/commons/net/ftp/FTPSClient.class | Bin 0 -> 8942 bytes bin/org/apache/commons/net/ftp/FTPSCommand.class | Bin 0 -> 991 bytes .../apache/commons/net/ftp/FTPSSocketFactory.class | Bin 0 -> 2344 bytes .../apache/commons/net/ftp/FTPSTrustManager.class | Bin 0 -> 1014 bytes .../net/ftp/parser/CompositeFileEntryParser.class | Bin 0 -> 1148 bytes .../ConfigurableFTPFileEntryParserImpl.class | Bin 0 -> 1646 bytes .../parser/DefaultFTPFileEntryParserFactory.class | Bin 0 -> 4791 bytes .../ftp/parser/EnterpriseUnixFTPEntryParser.class | Bin 0 -> 2537 bytes .../net/ftp/parser/FTPFileEntryParserFactory.class | Bin 0 -> 473 bytes .../net/ftp/parser/FTPTimestampParser.class | Bin 0 -> 409 bytes .../net/ftp/parser/FTPTimestampParserImpl.class | Bin 0 -> 5391 bytes .../commons/net/ftp/parser/MVSFTPEntryParser.class | Bin 0 -> 5338 bytes .../commons/net/ftp/parser/NTFTPEntryParser.class | Bin 0 -> 2451 bytes .../net/ftp/parser/NetwareFTPEntryParser.class | Bin 0 -> 2508 bytes .../commons/net/ftp/parser/OS2FTPEntryParser.class | Bin 0 -> 2433 bytes .../net/ftp/parser/OS400FTPEntryParser.class | Bin 0 -> 2810 bytes .../ftp/parser/ParserInitializationException.class | Bin 0 -> 759 bytes .../ftp/parser/RegexFTPFileEntryParserImpl.class | Bin 0 -> 2404 bytes .../net/ftp/parser/UnixFTPEntryParser.class | Bin 0 -> 4032 bytes .../commons/net/ftp/parser/VMSFTPEntryParser.class | Bin 0 -> 4700 bytes .../VMSVersioningFTPEntryParser$NameVersion.class | Bin 0 -> 756 bytes .../ftp/parser/VMSVersioningFTPEntryParser.class | Bin 0 -> 3550 bytes .../apache/commons/net/io/CopyStreamAdapter.class | Bin 0 -> 1814 bytes .../apache/commons/net/io/CopyStreamEvent.class | Bin 0 -> 917 bytes .../commons/net/io/CopyStreamException.class | Bin 0 -> 817 bytes .../apache/commons/net/io/CopyStreamListener.class | Bin 0 -> 267 bytes .../net/io/DotTerminatedMessageReader.class | Bin 0 -> 2598 bytes .../net/io/DotTerminatedMessageWriter.class | Bin 0 -> 2131 bytes .../commons/net/io/FromNetASCIIInputStream.class | Bin 0 -> 2061 bytes .../commons/net/io/FromNetASCIIOutputStream.class | Bin 0 -> 1548 bytes .../apache/commons/net/io/SocketInputStream.class | Bin 0 -> 701 bytes .../apache/commons/net/io/SocketOutputStream.class | Bin 0 -> 925 bytes .../commons/net/io/ToNetASCIIInputStream.class | Bin 0 -> 1526 bytes .../commons/net/io/ToNetASCIIOutputStream.class | Bin 0 -> 1051 bytes bin/org/apache/commons/net/io/Util.class | Bin 0 -> 3033 bytes bin/org/apache/commons/net/util/ListenerList.class | Bin 0 -> 1307 bytes .../commons/net/util/SubnetUtils$SubnetInfo.class | Bin 0 -> 3124 bytes bin/org/apache/commons/net/util/SubnetUtils.class | Bin 0 -> 4745 bytes bin/resources.ap_ | Bin 0 -> 11484 bytes default.properties | 11 + gen/com/lc8n/blauploader/R.java | 27 + org/apache/commons/net/DatagramSocketClient.java | 275 +++ org/apache/commons/net/DatagramSocketFactory.java | 67 + .../commons/net/DefaultDatagramSocketFactory.java | 75 + org/apache/commons/net/DefaultSocketFactory.java | 165 ++ .../net/MalformedServerReplyException.class | Bin 0 -> 344 bytes .../commons/net/MalformedServerReplyException.java | 55 + org/apache/commons/net/PrintCommandListener.java | 54 + org/apache/commons/net/ProtocolCommandEvent.class | Bin 0 -> 999 bytes org/apache/commons/net/ProtocolCommandEvent.java | 146 ++ .../commons/net/ProtocolCommandListener.class | Bin 0 -> 294 bytes .../commons/net/ProtocolCommandListener.java | 59 + .../commons/net/ProtocolCommandSupport.class | Bin 0 -> 1772 bytes org/apache/commons/net/ProtocolCommandSupport.java | 134 ++ org/apache/commons/net/SocketClient.class | Bin 0 -> 4744 bytes org/apache/commons/net/SocketClient.java | 586 +++++ org/apache/commons/net/bsd/RCommandClient.java | 402 ++++ org/apache/commons/net/bsd/RExecClient.java | 292 +++ org/apache/commons/net/bsd/RLoginClient.java | 131 ++ .../commons/net/chargen/CharGenTCPClient.java | 86 + .../commons/net/chargen/CharGenUDPClient.java | 129 ++ .../commons/net/daytime/DaytimeTCPClient.java | 92 + .../commons/net/daytime/DaytimeUDPClient.java | 84 + .../commons/net/discard/DiscardTCPClient.java | 67 + .../commons/net/discard/DiscardUDPClient.java | 97 + org/apache/commons/net/echo/EchoTCPClient.java | 72 + org/apache/commons/net/echo/EchoUDPClient.java | 101 + org/apache/commons/net/finger/FingerClient.java | 197 ++ org/apache/commons/net/ftp/Configurable.class | Bin 0 -> 202 bytes org/apache/commons/net/ftp/Configurable.java | 35 + org/apache/commons/net/ftp/FTP.class | Bin 0 -> 9922 bytes org/apache/commons/net/ftp/FTP.java | 1513 ++++++++++++ org/apache/commons/net/ftp/FTPClient.class | Bin 0 -> 16187 bytes org/apache/commons/net/ftp/FTPClient.java | 2447 ++++++++++++++++++++ org/apache/commons/net/ftp/FTPClientConfig.class | Bin 0 -> 4524 bytes org/apache/commons/net/ftp/FTPClientConfig.java | 580 +++++ org/apache/commons/net/ftp/FTPCommand.class | Bin 0 -> 2624 bytes org/apache/commons/net/ftp/FTPCommand.java | 131 ++ .../net/ftp/FTPConnectionClosedException.class | Bin 0 -> 346 bytes .../net/ftp/FTPConnectionClosedException.java | 55 + org/apache/commons/net/ftp/FTPFile.class | Bin 0 -> 2732 bytes org/apache/commons/net/ftp/FTPFile.java | 392 ++++ .../commons/net/ftp/FTPFileEntryParser.class | Bin 0 -> 499 bytes org/apache/commons/net/ftp/FTPFileEntryParser.java | 152 ++ .../commons/net/ftp/FTPFileEntryParserImpl.class | Bin 0 -> 1098 bytes .../commons/net/ftp/FTPFileEntryParserImpl.java | 85 + .../commons/net/ftp/FTPListParseEngine.class | Bin 0 -> 2970 bytes org/apache/commons/net/ftp/FTPListParseEngine.java | 290 +++ org/apache/commons/net/ftp/FTPReply.class | Bin 0 -> 4171 bytes org/apache/commons/net/ftp/FTPReply.java | 240 ++ org/apache/commons/net/ftp/FTPSClient.java | 533 +++++ org/apache/commons/net/ftp/FTPSCommand.java | 50 + org/apache/commons/net/ftp/FTPSSocketFactory.java | 82 + org/apache/commons/net/ftp/FTPSTrustManager.java | 54 + .../net/ftp/parser/CompositeFileEntryParser.class | Bin 0 -> 882 bytes .../net/ftp/parser/CompositeFileEntryParser.java | 72 + .../ConfigurableFTPFileEntryParserImpl.class | Bin 0 -> 1378 bytes .../parser/ConfigurableFTPFileEntryParserImpl.java | 116 + .../parser/DefaultFTPFileEntryParserFactory.class | Bin 0 -> 4098 bytes .../parser/DefaultFTPFileEntryParserFactory.java | 247 ++ .../ftp/parser/EnterpriseUnixFTPEntryParser.java | 166 ++ .../net/ftp/parser/FTPFileEntryParserFactory.class | Bin 0 -> 473 bytes .../net/ftp/parser/FTPFileEntryParserFactory.java | 68 + .../net/ftp/parser/FTPTimestampParser.class | Bin 0 -> 409 bytes .../commons/net/ftp/parser/FTPTimestampParser.java | 52 + .../net/ftp/parser/FTPTimestampParserImpl.class | Bin 0 -> 4464 bytes .../net/ftp/parser/FTPTimestampParserImpl.java | 301 +++ .../commons/net/ftp/parser/MVSFTPEntryParser.class | Bin 0 -> 4638 bytes .../commons/net/ftp/parser/MVSFTPEntryParser.java | 495 ++++ .../commons/net/ftp/parser/NTFTPEntryParser.class | Bin 0 -> 2100 bytes .../commons/net/ftp/parser/NTFTPEntryParser.java | 147 ++ .../net/ftp/parser/NetwareFTPEntryParser.class | Bin 0 -> 2169 bytes .../net/ftp/parser/NetwareFTPEntryParser.java | 176 ++ .../commons/net/ftp/parser/OS2FTPEntryParser.class | Bin 0 -> 2062 bytes .../commons/net/ftp/parser/OS2FTPEntryParser.java | 147 ++ .../net/ftp/parser/OS400FTPEntryParser.class | Bin 0 -> 2427 bytes .../net/ftp/parser/OS400FTPEntryParser.java | 158 ++ .../ftp/parser/ParserInitializationException.class | Bin 0 -> 548 bytes .../ftp/parser/ParserInitializationException.java | 65 + .../ftp/parser/RegexFTPFileEntryParserImpl.class | Bin 0 -> 2082 bytes .../ftp/parser/RegexFTPFileEntryParserImpl.java | 155 ++ .../net/ftp/parser/UnixFTPEntryParser.class | Bin 0 -> 3748 bytes .../commons/net/ftp/parser/UnixFTPEntryParser.java | 295 +++ .../commons/net/ftp/parser/VMSFTPEntryParser.class | Bin 0 -> 4251 bytes .../commons/net/ftp/parser/VMSFTPEntryParser.java | 288 +++ .../VMSVersioningFTPEntryParser$NameVersion.class | Bin 0 -> 605 bytes .../ftp/parser/VMSVersioningFTPEntryParser.class | Bin 0 -> 2768 bytes .../ftp/parser/VMSVersioningFTPEntryParser.java | 183 ++ org/apache/commons/net/io/CopyStreamAdapter.java | 122 + org/apache/commons/net/io/CopyStreamEvent.class | Bin 0 -> 701 bytes org/apache/commons/net/io/CopyStreamEvent.java | 98 + .../commons/net/io/CopyStreamException.class | Bin 0 -> 593 bytes org/apache/commons/net/io/CopyStreamException.java | 71 + org/apache/commons/net/io/CopyStreamListener.class | Bin 0 -> 267 bytes org/apache/commons/net/io/CopyStreamListener.java | 72 + .../commons/net/io/DotTerminatedMessageReader.java | 280 +++ .../commons/net/io/DotTerminatedMessageWriter.java | 215 ++ .../commons/net/io/FromNetASCIIInputStream.class | Bin 0 -> 1844 bytes .../commons/net/io/FromNetASCIIInputStream.java | 205 ++ .../commons/net/io/FromNetASCIIOutputStream.java | 174 ++ org/apache/commons/net/io/SocketInputStream.class | Bin 0 -> 527 bytes org/apache/commons/net/io/SocketInputStream.java | 69 + org/apache/commons/net/io/SocketOutputStream.class | Bin 0 -> 690 bytes org/apache/commons/net/io/SocketOutputStream.java | 89 + .../commons/net/io/ToNetASCIIInputStream.java | 181 ++ .../commons/net/io/ToNetASCIIOutputStream.class | Bin 0 -> 817 bytes .../commons/net/io/ToNetASCIIOutputStream.java | 119 + org/apache/commons/net/io/Util.class | Bin 0 -> 2431 bytes org/apache/commons/net/io/Util.java | 334 +++ org/apache/commons/net/nntp/Article.java | 253 ++ org/apache/commons/net/nntp/ArticlePointer.java | 39 + org/apache/commons/net/nntp/NNTP.java | 1022 ++++++++ org/apache/commons/net/nntp/NNTPClient.java | 1285 ++++++++++ org/apache/commons/net/nntp/NNTPCommand.java | 83 + .../net/nntp/NNTPConnectionClosedException.java | 56 + org/apache/commons/net/nntp/NNTPReply.java | 209 ++ .../commons/net/nntp/NewGroupsOrNewsQuery.java | 283 +++ org/apache/commons/net/nntp/NewsgroupInfo.java | 155 ++ org/apache/commons/net/nntp/SimpleNNTPHeader.java | 164 ++ org/apache/commons/net/nntp/Threadable.java | 34 + org/apache/commons/net/nntp/Threader.java | 481 ++++ org/apache/commons/net/ntp/NTPUDPClient.java | 140 ++ org/apache/commons/net/ntp/NtpUtils.java | 113 + org/apache/commons/net/ntp/NtpV3Impl.java | 583 +++++ org/apache/commons/net/ntp/NtpV3Packet.java | 236 ++ org/apache/commons/net/ntp/TimeInfo.java | 295 +++ org/apache/commons/net/ntp/TimeStamp.java | 490 ++++ org/apache/commons/net/pop3/POP3.java | 358 +++ org/apache/commons/net/pop3/POP3Client.java | 552 +++++ org/apache/commons/net/pop3/POP3Command.java | 72 + org/apache/commons/net/pop3/POP3MessageInfo.java | 82 + org/apache/commons/net/pop3/POP3Reply.java | 38 + org/apache/commons/net/smtp/RelayPath.java | 102 + org/apache/commons/net/smtp/SMTP.java | 777 +++++++ org/apache/commons/net/smtp/SMTPClient.java | 607 +++++ org/apache/commons/net/smtp/SMTPCommand.java | 91 + .../net/smtp/SMTPConnectionClosedException.java | 56 + org/apache/commons/net/smtp/SMTPReply.java | 167 ++ org/apache/commons/net/smtp/SimpleSMTPHeader.java | 153 ++ .../commons/net/telnet/EchoOptionHandler.java | 90 + .../net/telnet/InvalidTelnetOptionException.java | 62 + .../commons/net/telnet/SimpleOptionHandler.java | 96 + .../net/telnet/SuppressGAOptionHandler.java | 89 + org/apache/commons/net/telnet/Telnet.java | 1317 +++++++++++ org/apache/commons/net/telnet/TelnetClient.java | 306 +++ org/apache/commons/net/telnet/TelnetCommand.java | 132 ++ .../commons/net/telnet/TelnetInputStream.java | 630 +++++ .../net/telnet/TelnetNotificationHandler.java | 66 + org/apache/commons/net/telnet/TelnetOption.java | 193 ++ .../commons/net/telnet/TelnetOptionHandler.java | 272 +++ .../commons/net/telnet/TelnetOutputStream.java | 152 ++ .../net/telnet/TerminalTypeOptionHandler.java | 136 ++ .../net/telnet/WindowSizeOptionHandler.java | 188 ++ org/apache/commons/net/tftp/TFTP.java | 301 +++ org/apache/commons/net/tftp/TFTPAckPacket.java | 158 ++ org/apache/commons/net/tftp/TFTPClient.java | 610 +++++ org/apache/commons/net/tftp/TFTPDataPacket.java | 254 ++ org/apache/commons/net/tftp/TFTPErrorPacket.java | 226 ++ org/apache/commons/net/tftp/TFTPPacket.java | 247 ++ .../commons/net/tftp/TFTPPacketException.java | 57 + .../commons/net/tftp/TFTPReadRequestPacket.java | 80 + org/apache/commons/net/tftp/TFTPRequestPacket.java | 253 ++ .../commons/net/tftp/TFTPWriteRequestPacket.java | 79 + org/apache/commons/net/time/TimeTCPClient.java | 109 + org/apache/commons/net/time/TimeUDPClient.java | 127 + org/apache/commons/net/util/ListenerList.class | Bin 0 -> 1085 bytes org/apache/commons/net/util/ListenerList.java | 63 + org/apache/commons/net/util/SubnetUtils.java | 211 ++ org/apache/commons/net/whois/WhoisClient.java | 109 + res/drawable-hdpi/icon.png | Bin 0 -> 4147 bytes res/drawable-ldpi/icon.png | Bin 0 -> 1723 bytes res/drawable-mdpi/icon.png | Bin 0 -> 2574 bytes res/layout/filerow.xml | 7 + res/layout/main.xml | 19 + res/values/strings.xml | 5 + src/com/lc8n/blauploader/FileBrowser.java | 198 ++ src/com/lc8n/blauploader/FileUpload.java | 76 + src/com/lc8n/blauploader/ProgressInputStream.java | 97 + .../apache/commons/net/DatagramSocketClient.java | 275 +++ .../apache/commons/net/DatagramSocketFactory.java | 67 + .../commons/net/DefaultDatagramSocketFactory.java | 75 + .../apache/commons/net/DefaultSocketFactory.java | 165 ++ .../commons/net/MalformedServerReplyException.java | 55 + .../apache/commons/net/PrintCommandListener.java | 54 + .../apache/commons/net/ProtocolCommandEvent.java | 146 ++ .../commons/net/ProtocolCommandListener.java | 59 + .../apache/commons/net/ProtocolCommandSupport.java | 134 ++ src/org/apache/commons/net/SocketClient.java | 586 +++++ src/org/apache/commons/net/ftp/Configurable.java | 35 + src/org/apache/commons/net/ftp/FTP.java | 1513 ++++++++++++ src/org/apache/commons/net/ftp/FTPClient.java | 2447 ++++++++++++++++++++ .../apache/commons/net/ftp/FTPClientConfig.java | 580 +++++ src/org/apache/commons/net/ftp/FTPCommand.java | 131 ++ .../net/ftp/FTPConnectionClosedException.java | 55 + src/org/apache/commons/net/ftp/FTPFile.java | 392 ++++ .../apache/commons/net/ftp/FTPFileEntryParser.java | 152 ++ .../commons/net/ftp/FTPFileEntryParserImpl.java | 85 + .../apache/commons/net/ftp/FTPListParseEngine.java | 290 +++ src/org/apache/commons/net/ftp/FTPReply.java | 240 ++ src/org/apache/commons/net/ftp/FTPSClient.java | 533 +++++ src/org/apache/commons/net/ftp/FTPSCommand.java | 50 + .../apache/commons/net/ftp/FTPSSocketFactory.java | 82 + .../apache/commons/net/ftp/FTPSTrustManager.java | 54 + .../net/ftp/parser/CompositeFileEntryParser.java | 72 + .../parser/ConfigurableFTPFileEntryParserImpl.java | 116 + .../parser/DefaultFTPFileEntryParserFactory.java | 247 ++ .../ftp/parser/EnterpriseUnixFTPEntryParser.java | 166 ++ .../net/ftp/parser/FTPFileEntryParserFactory.java | 68 + .../commons/net/ftp/parser/FTPTimestampParser.java | 52 + .../net/ftp/parser/FTPTimestampParserImpl.java | 301 +++ .../commons/net/ftp/parser/MVSFTPEntryParser.java | 495 ++++ .../commons/net/ftp/parser/NTFTPEntryParser.java | 147 ++ .../net/ftp/parser/NetwareFTPEntryParser.java | 176 ++ .../commons/net/ftp/parser/OS2FTPEntryParser.java | 147 ++ .../net/ftp/parser/OS400FTPEntryParser.java | 158 ++ .../ftp/parser/ParserInitializationException.java | 65 + .../ftp/parser/RegexFTPFileEntryParserImpl.java | 155 ++ .../commons/net/ftp/parser/UnixFTPEntryParser.java | 295 +++ .../commons/net/ftp/parser/VMSFTPEntryParser.java | 288 +++ .../ftp/parser/VMSVersioningFTPEntryParser.java | 183 ++ .../apache/commons/net/io/CopyStreamAdapter.java | 122 + src/org/apache/commons/net/io/CopyStreamEvent.java | 98 + .../apache/commons/net/io/CopyStreamException.java | 71 + .../apache/commons/net/io/CopyStreamListener.java | 72 + .../commons/net/io/DotTerminatedMessageReader.java | 280 +++ .../commons/net/io/DotTerminatedMessageWriter.java | 215 ++ .../commons/net/io/FromNetASCIIInputStream.java | 205 ++ .../commons/net/io/FromNetASCIIOutputStream.java | 174 ++ .../apache/commons/net/io/SocketInputStream.java | 69 + .../apache/commons/net/io/SocketOutputStream.java | 89 + .../commons/net/io/ToNetASCIIInputStream.java | 181 ++ .../commons/net/io/ToNetASCIIOutputStream.java | 119 + src/org/apache/commons/net/io/Util.java | 334 +++ src/org/apache/commons/net/util/ListenerList.java | 63 + src/org/apache/commons/net/util/SubnetUtils.java | 211 ++ 310 files changed, 44914 insertions(+) create mode 100644 AndroidManifest.xml create mode 100644 README create mode 100644 bin/blauploader.apk create mode 100644 bin/classes.dex create mode 100644 bin/com/lc8n/blauploader/FileBrowser$1.class create mode 100644 bin/com/lc8n/blauploader/FileBrowser.class create mode 100644 bin/com/lc8n/blauploader/FileUpload.class create mode 100644 bin/com/lc8n/blauploader/ProgressInputStream.class create mode 100644 bin/com/lc8n/blauploader/R$attr.class create mode 100644 bin/com/lc8n/blauploader/R$drawable.class create mode 100644 bin/com/lc8n/blauploader/R$id.class create mode 100644 bin/com/lc8n/blauploader/R$layout.class create mode 100644 bin/com/lc8n/blauploader/R$string.class create mode 100644 bin/com/lc8n/blauploader/R.class create mode 100644 bin/org/apache/commons/net/DatagramSocketClient.class create mode 100644 bin/org/apache/commons/net/DatagramSocketFactory.class create mode 100644 bin/org/apache/commons/net/DefaultDatagramSocketFactory.class create mode 100644 bin/org/apache/commons/net/DefaultSocketFactory.class create mode 100644 bin/org/apache/commons/net/MalformedServerReplyException.class create mode 100644 bin/org/apache/commons/net/PrintCommandListener.class create mode 100644 bin/org/apache/commons/net/ProtocolCommandEvent.class create mode 100644 bin/org/apache/commons/net/ProtocolCommandListener.class create mode 100644 bin/org/apache/commons/net/ProtocolCommandSupport.class create mode 100644 bin/org/apache/commons/net/SocketClient.class create mode 100644 bin/org/apache/commons/net/ftp/Configurable.class create mode 100644 bin/org/apache/commons/net/ftp/FTP.class create mode 100644 bin/org/apache/commons/net/ftp/FTPClient.class create mode 100644 bin/org/apache/commons/net/ftp/FTPClientConfig.class create mode 100644 bin/org/apache/commons/net/ftp/FTPCommand.class create mode 100644 bin/org/apache/commons/net/ftp/FTPConnectionClosedException.class create mode 100644 bin/org/apache/commons/net/ftp/FTPFile.class create mode 100644 bin/org/apache/commons/net/ftp/FTPFileEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class create mode 100644 bin/org/apache/commons/net/ftp/FTPListParseEngine.class create mode 100644 bin/org/apache/commons/net/ftp/FTPReply.class create mode 100644 bin/org/apache/commons/net/ftp/FTPSClient.class create mode 100644 bin/org/apache/commons/net/ftp/FTPSCommand.class create mode 100644 bin/org/apache/commons/net/ftp/FTPSSocketFactory.class create mode 100644 bin/org/apache/commons/net/ftp/FTPSTrustManager.class create mode 100644 bin/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class create mode 100644 bin/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class create mode 100644 bin/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class create mode 100644 bin/org/apache/commons/net/ftp/parser/FTPTimestampParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class create mode 100644 bin/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/ParserInitializationException.class create mode 100644 bin/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class create mode 100644 bin/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class create mode 100644 bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class create mode 100644 bin/org/apache/commons/net/io/CopyStreamAdapter.class create mode 100644 bin/org/apache/commons/net/io/CopyStreamEvent.class create mode 100644 bin/org/apache/commons/net/io/CopyStreamException.class create mode 100644 bin/org/apache/commons/net/io/CopyStreamListener.class create mode 100644 bin/org/apache/commons/net/io/DotTerminatedMessageReader.class create mode 100644 bin/org/apache/commons/net/io/DotTerminatedMessageWriter.class create mode 100644 bin/org/apache/commons/net/io/FromNetASCIIInputStream.class create mode 100644 bin/org/apache/commons/net/io/FromNetASCIIOutputStream.class create mode 100644 bin/org/apache/commons/net/io/SocketInputStream.class create mode 100644 bin/org/apache/commons/net/io/SocketOutputStream.class create mode 100644 bin/org/apache/commons/net/io/ToNetASCIIInputStream.class create mode 100644 bin/org/apache/commons/net/io/ToNetASCIIOutputStream.class create mode 100644 bin/org/apache/commons/net/io/Util.class create mode 100644 bin/org/apache/commons/net/util/ListenerList.class create mode 100644 bin/org/apache/commons/net/util/SubnetUtils$SubnetInfo.class create mode 100644 bin/org/apache/commons/net/util/SubnetUtils.class create mode 100644 bin/resources.ap_ create mode 100644 default.properties create mode 100644 gen/com/lc8n/blauploader/R.java create mode 100644 org/apache/commons/net/DatagramSocketClient.java create mode 100644 org/apache/commons/net/DatagramSocketFactory.java create mode 100644 org/apache/commons/net/DefaultDatagramSocketFactory.java create mode 100644 org/apache/commons/net/DefaultSocketFactory.java create mode 100644 org/apache/commons/net/MalformedServerReplyException.class create mode 100644 org/apache/commons/net/MalformedServerReplyException.java create mode 100644 org/apache/commons/net/PrintCommandListener.java create mode 100644 org/apache/commons/net/ProtocolCommandEvent.class create mode 100644 org/apache/commons/net/ProtocolCommandEvent.java create mode 100644 org/apache/commons/net/ProtocolCommandListener.class create mode 100644 org/apache/commons/net/ProtocolCommandListener.java create mode 100644 org/apache/commons/net/ProtocolCommandSupport.class create mode 100644 org/apache/commons/net/ProtocolCommandSupport.java create mode 100644 org/apache/commons/net/SocketClient.class create mode 100644 org/apache/commons/net/SocketClient.java create mode 100644 org/apache/commons/net/bsd/RCommandClient.java create mode 100644 org/apache/commons/net/bsd/RExecClient.java create mode 100644 org/apache/commons/net/bsd/RLoginClient.java create mode 100644 org/apache/commons/net/chargen/CharGenTCPClient.java create mode 100644 org/apache/commons/net/chargen/CharGenUDPClient.java create mode 100644 org/apache/commons/net/daytime/DaytimeTCPClient.java create mode 100644 org/apache/commons/net/daytime/DaytimeUDPClient.java create mode 100644 org/apache/commons/net/discard/DiscardTCPClient.java create mode 100644 org/apache/commons/net/discard/DiscardUDPClient.java create mode 100644 org/apache/commons/net/echo/EchoTCPClient.java create mode 100644 org/apache/commons/net/echo/EchoUDPClient.java create mode 100644 org/apache/commons/net/finger/FingerClient.java create mode 100644 org/apache/commons/net/ftp/Configurable.class create mode 100644 org/apache/commons/net/ftp/Configurable.java create mode 100644 org/apache/commons/net/ftp/FTP.class create mode 100644 org/apache/commons/net/ftp/FTP.java create mode 100644 org/apache/commons/net/ftp/FTPClient.class create mode 100644 org/apache/commons/net/ftp/FTPClient.java create mode 100644 org/apache/commons/net/ftp/FTPClientConfig.class create mode 100644 org/apache/commons/net/ftp/FTPClientConfig.java create mode 100644 org/apache/commons/net/ftp/FTPCommand.class create mode 100644 org/apache/commons/net/ftp/FTPCommand.java create mode 100644 org/apache/commons/net/ftp/FTPConnectionClosedException.class create mode 100644 org/apache/commons/net/ftp/FTPConnectionClosedException.java create mode 100644 org/apache/commons/net/ftp/FTPFile.class create mode 100644 org/apache/commons/net/ftp/FTPFile.java create mode 100644 org/apache/commons/net/ftp/FTPFileEntryParser.class create mode 100644 org/apache/commons/net/ftp/FTPFileEntryParser.java create mode 100644 org/apache/commons/net/ftp/FTPFileEntryParserImpl.class create mode 100644 org/apache/commons/net/ftp/FTPFileEntryParserImpl.java create mode 100644 org/apache/commons/net/ftp/FTPListParseEngine.class create mode 100644 org/apache/commons/net/ftp/FTPListParseEngine.java create mode 100644 org/apache/commons/net/ftp/FTPReply.class create mode 100644 org/apache/commons/net/ftp/FTPReply.java create mode 100644 org/apache/commons/net/ftp/FTPSClient.java create mode 100644 org/apache/commons/net/ftp/FTPSCommand.java create mode 100644 org/apache/commons/net/ftp/FTPSSocketFactory.java create mode 100644 org/apache/commons/net/ftp/FTPSTrustManager.java create mode 100644 org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class create mode 100644 org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java create mode 100644 org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class create mode 100644 org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java create mode 100644 org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class create mode 100644 org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java create mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParser.class create mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParser.java create mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class create mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java create mode 100644 org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/NTFTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/NTFTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/ParserInitializationException.class create mode 100644 org/apache/commons/net/ftp/parser/ParserInitializationException.java create mode 100644 org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class create mode 100644 org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java create mode 100644 org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java create mode 100644 org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class create mode 100644 org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class create mode 100644 org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java create mode 100644 org/apache/commons/net/io/CopyStreamAdapter.java create mode 100644 org/apache/commons/net/io/CopyStreamEvent.class create mode 100644 org/apache/commons/net/io/CopyStreamEvent.java create mode 100644 org/apache/commons/net/io/CopyStreamException.class create mode 100644 org/apache/commons/net/io/CopyStreamException.java create mode 100644 org/apache/commons/net/io/CopyStreamListener.class create mode 100644 org/apache/commons/net/io/CopyStreamListener.java create mode 100644 org/apache/commons/net/io/DotTerminatedMessageReader.java create mode 100644 org/apache/commons/net/io/DotTerminatedMessageWriter.java create mode 100644 org/apache/commons/net/io/FromNetASCIIInputStream.class create mode 100644 org/apache/commons/net/io/FromNetASCIIInputStream.java create mode 100644 org/apache/commons/net/io/FromNetASCIIOutputStream.java create mode 100644 org/apache/commons/net/io/SocketInputStream.class create mode 100644 org/apache/commons/net/io/SocketInputStream.java create mode 100644 org/apache/commons/net/io/SocketOutputStream.class create mode 100644 org/apache/commons/net/io/SocketOutputStream.java create mode 100644 org/apache/commons/net/io/ToNetASCIIInputStream.java create mode 100644 org/apache/commons/net/io/ToNetASCIIOutputStream.class create mode 100644 org/apache/commons/net/io/ToNetASCIIOutputStream.java create mode 100644 org/apache/commons/net/io/Util.class create mode 100644 org/apache/commons/net/io/Util.java create mode 100644 org/apache/commons/net/nntp/Article.java create mode 100644 org/apache/commons/net/nntp/ArticlePointer.java create mode 100644 org/apache/commons/net/nntp/NNTP.java create mode 100644 org/apache/commons/net/nntp/NNTPClient.java create mode 100644 org/apache/commons/net/nntp/NNTPCommand.java create mode 100644 org/apache/commons/net/nntp/NNTPConnectionClosedException.java create mode 100644 org/apache/commons/net/nntp/NNTPReply.java create mode 100644 org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java create mode 100644 org/apache/commons/net/nntp/NewsgroupInfo.java create mode 100644 org/apache/commons/net/nntp/SimpleNNTPHeader.java create mode 100644 org/apache/commons/net/nntp/Threadable.java create mode 100644 org/apache/commons/net/nntp/Threader.java create mode 100644 org/apache/commons/net/ntp/NTPUDPClient.java create mode 100644 org/apache/commons/net/ntp/NtpUtils.java create mode 100644 org/apache/commons/net/ntp/NtpV3Impl.java create mode 100644 org/apache/commons/net/ntp/NtpV3Packet.java create mode 100644 org/apache/commons/net/ntp/TimeInfo.java create mode 100644 org/apache/commons/net/ntp/TimeStamp.java create mode 100644 org/apache/commons/net/pop3/POP3.java create mode 100644 org/apache/commons/net/pop3/POP3Client.java create mode 100644 org/apache/commons/net/pop3/POP3Command.java create mode 100644 org/apache/commons/net/pop3/POP3MessageInfo.java create mode 100644 org/apache/commons/net/pop3/POP3Reply.java create mode 100644 org/apache/commons/net/smtp/RelayPath.java create mode 100644 org/apache/commons/net/smtp/SMTP.java create mode 100644 org/apache/commons/net/smtp/SMTPClient.java create mode 100644 org/apache/commons/net/smtp/SMTPCommand.java create mode 100644 org/apache/commons/net/smtp/SMTPConnectionClosedException.java create mode 100644 org/apache/commons/net/smtp/SMTPReply.java create mode 100644 org/apache/commons/net/smtp/SimpleSMTPHeader.java create mode 100644 org/apache/commons/net/telnet/EchoOptionHandler.java create mode 100644 org/apache/commons/net/telnet/InvalidTelnetOptionException.java create mode 100644 org/apache/commons/net/telnet/SimpleOptionHandler.java create mode 100644 org/apache/commons/net/telnet/SuppressGAOptionHandler.java create mode 100644 org/apache/commons/net/telnet/Telnet.java create mode 100644 org/apache/commons/net/telnet/TelnetClient.java create mode 100644 org/apache/commons/net/telnet/TelnetCommand.java create mode 100644 org/apache/commons/net/telnet/TelnetInputStream.java create mode 100644 org/apache/commons/net/telnet/TelnetNotificationHandler.java create mode 100644 org/apache/commons/net/telnet/TelnetOption.java create mode 100644 org/apache/commons/net/telnet/TelnetOptionHandler.java create mode 100644 org/apache/commons/net/telnet/TelnetOutputStream.java create mode 100644 org/apache/commons/net/telnet/TerminalTypeOptionHandler.java create mode 100644 org/apache/commons/net/telnet/WindowSizeOptionHandler.java create mode 100644 org/apache/commons/net/tftp/TFTP.java create mode 100644 org/apache/commons/net/tftp/TFTPAckPacket.java create mode 100644 org/apache/commons/net/tftp/TFTPClient.java create mode 100644 org/apache/commons/net/tftp/TFTPDataPacket.java create mode 100644 org/apache/commons/net/tftp/TFTPErrorPacket.java create mode 100644 org/apache/commons/net/tftp/TFTPPacket.java create mode 100644 org/apache/commons/net/tftp/TFTPPacketException.java create mode 100644 org/apache/commons/net/tftp/TFTPReadRequestPacket.java create mode 100644 org/apache/commons/net/tftp/TFTPRequestPacket.java create mode 100644 org/apache/commons/net/tftp/TFTPWriteRequestPacket.java create mode 100644 org/apache/commons/net/time/TimeTCPClient.java create mode 100644 org/apache/commons/net/time/TimeUDPClient.java create mode 100644 org/apache/commons/net/util/ListenerList.class create mode 100644 org/apache/commons/net/util/ListenerList.java create mode 100644 org/apache/commons/net/util/SubnetUtils.java create mode 100644 org/apache/commons/net/whois/WhoisClient.java create mode 100644 res/drawable-hdpi/icon.png create mode 100644 res/drawable-ldpi/icon.png create mode 100644 res/drawable-mdpi/icon.png create mode 100644 res/layout/filerow.xml create mode 100644 res/layout/main.xml create mode 100644 res/values/strings.xml create mode 100644 src/com/lc8n/blauploader/FileBrowser.java create mode 100644 src/com/lc8n/blauploader/FileUpload.java create mode 100644 src/com/lc8n/blauploader/ProgressInputStream.java create mode 100644 src/org/apache/commons/net/DatagramSocketClient.java create mode 100644 src/org/apache/commons/net/DatagramSocketFactory.java create mode 100644 src/org/apache/commons/net/DefaultDatagramSocketFactory.java create mode 100644 src/org/apache/commons/net/DefaultSocketFactory.java create mode 100644 src/org/apache/commons/net/MalformedServerReplyException.java create mode 100644 src/org/apache/commons/net/PrintCommandListener.java create mode 100644 src/org/apache/commons/net/ProtocolCommandEvent.java create mode 100644 src/org/apache/commons/net/ProtocolCommandListener.java create mode 100644 src/org/apache/commons/net/ProtocolCommandSupport.java create mode 100644 src/org/apache/commons/net/SocketClient.java create mode 100644 src/org/apache/commons/net/ftp/Configurable.java create mode 100644 src/org/apache/commons/net/ftp/FTP.java create mode 100644 src/org/apache/commons/net/ftp/FTPClient.java create mode 100644 src/org/apache/commons/net/ftp/FTPClientConfig.java create mode 100644 src/org/apache/commons/net/ftp/FTPCommand.java create mode 100644 src/org/apache/commons/net/ftp/FTPConnectionClosedException.java create mode 100644 src/org/apache/commons/net/ftp/FTPFile.java create mode 100644 src/org/apache/commons/net/ftp/FTPFileEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java create mode 100644 src/org/apache/commons/net/ftp/FTPListParseEngine.java create mode 100644 src/org/apache/commons/net/ftp/FTPReply.java create mode 100644 src/org/apache/commons/net/ftp/FTPSClient.java create mode 100644 src/org/apache/commons/net/ftp/FTPSCommand.java create mode 100644 src/org/apache/commons/net/ftp/FTPSSocketFactory.java create mode 100644 src/org/apache/commons/net/ftp/FTPSTrustManager.java create mode 100644 src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java create mode 100644 src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java create mode 100644 src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java create mode 100644 src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java create mode 100644 src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/ParserInitializationException.java create mode 100644 src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java create mode 100644 src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java create mode 100644 src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java create mode 100644 src/org/apache/commons/net/io/CopyStreamAdapter.java create mode 100644 src/org/apache/commons/net/io/CopyStreamEvent.java create mode 100644 src/org/apache/commons/net/io/CopyStreamException.java create mode 100644 src/org/apache/commons/net/io/CopyStreamListener.java create mode 100644 src/org/apache/commons/net/io/DotTerminatedMessageReader.java create mode 100644 src/org/apache/commons/net/io/DotTerminatedMessageWriter.java create mode 100644 src/org/apache/commons/net/io/FromNetASCIIInputStream.java create mode 100644 src/org/apache/commons/net/io/FromNetASCIIOutputStream.java create mode 100644 src/org/apache/commons/net/io/SocketInputStream.java create mode 100644 src/org/apache/commons/net/io/SocketOutputStream.java create mode 100644 src/org/apache/commons/net/io/ToNetASCIIInputStream.java create mode 100644 src/org/apache/commons/net/io/ToNetASCIIOutputStream.java create mode 100644 src/org/apache/commons/net/io/Util.java create mode 100644 src/org/apache/commons/net/util/ListenerList.java create mode 100644 src/org/apache/commons/net/util/SubnetUtils.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..b78b9d8 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..6b4a12b --- /dev/null +++ b/README @@ -0,0 +1,5 @@ +One day, this might be a readme file. + +Right now, it's not a readme file. + +Sorry. diff --git a/bin/blauploader.apk b/bin/blauploader.apk new file mode 100644 index 0000000..1734ab9 Binary files /dev/null and b/bin/blauploader.apk differ diff --git a/bin/classes.dex b/bin/classes.dex new file mode 100644 index 0000000..f601faa Binary files /dev/null and b/bin/classes.dex differ diff --git a/bin/com/lc8n/blauploader/FileBrowser$1.class b/bin/com/lc8n/blauploader/FileBrowser$1.class new file mode 100644 index 0000000..cda1330 Binary files /dev/null and b/bin/com/lc8n/blauploader/FileBrowser$1.class differ diff --git a/bin/com/lc8n/blauploader/FileBrowser.class b/bin/com/lc8n/blauploader/FileBrowser.class new file mode 100644 index 0000000..a9859ef Binary files /dev/null and b/bin/com/lc8n/blauploader/FileBrowser.class differ diff --git a/bin/com/lc8n/blauploader/FileUpload.class b/bin/com/lc8n/blauploader/FileUpload.class new file mode 100644 index 0000000..2dcb505 Binary files /dev/null and b/bin/com/lc8n/blauploader/FileUpload.class differ diff --git a/bin/com/lc8n/blauploader/ProgressInputStream.class b/bin/com/lc8n/blauploader/ProgressInputStream.class new file mode 100644 index 0000000..a5bf861 Binary files /dev/null and b/bin/com/lc8n/blauploader/ProgressInputStream.class differ diff --git a/bin/com/lc8n/blauploader/R$attr.class b/bin/com/lc8n/blauploader/R$attr.class new file mode 100644 index 0000000..b463ed9 Binary files /dev/null and b/bin/com/lc8n/blauploader/R$attr.class differ diff --git a/bin/com/lc8n/blauploader/R$drawable.class b/bin/com/lc8n/blauploader/R$drawable.class new file mode 100644 index 0000000..a29ff28 Binary files /dev/null and b/bin/com/lc8n/blauploader/R$drawable.class differ diff --git a/bin/com/lc8n/blauploader/R$id.class b/bin/com/lc8n/blauploader/R$id.class new file mode 100644 index 0000000..bc1a3b5 Binary files /dev/null and b/bin/com/lc8n/blauploader/R$id.class differ diff --git a/bin/com/lc8n/blauploader/R$layout.class b/bin/com/lc8n/blauploader/R$layout.class new file mode 100644 index 0000000..184a81e Binary files /dev/null and b/bin/com/lc8n/blauploader/R$layout.class differ diff --git a/bin/com/lc8n/blauploader/R$string.class b/bin/com/lc8n/blauploader/R$string.class new file mode 100644 index 0000000..e438feb Binary files /dev/null and b/bin/com/lc8n/blauploader/R$string.class differ diff --git a/bin/com/lc8n/blauploader/R.class b/bin/com/lc8n/blauploader/R.class new file mode 100644 index 0000000..32da83a Binary files /dev/null and b/bin/com/lc8n/blauploader/R.class differ diff --git a/bin/org/apache/commons/net/DatagramSocketClient.class b/bin/org/apache/commons/net/DatagramSocketClient.class new file mode 100644 index 0000000..9962b0c Binary files /dev/null and b/bin/org/apache/commons/net/DatagramSocketClient.class differ diff --git a/bin/org/apache/commons/net/DatagramSocketFactory.class b/bin/org/apache/commons/net/DatagramSocketFactory.class new file mode 100644 index 0000000..e745d32 Binary files /dev/null and b/bin/org/apache/commons/net/DatagramSocketFactory.class differ diff --git a/bin/org/apache/commons/net/DefaultDatagramSocketFactory.class b/bin/org/apache/commons/net/DefaultDatagramSocketFactory.class new file mode 100644 index 0000000..ce94e85 Binary files /dev/null and b/bin/org/apache/commons/net/DefaultDatagramSocketFactory.class differ diff --git a/bin/org/apache/commons/net/DefaultSocketFactory.class b/bin/org/apache/commons/net/DefaultSocketFactory.class new file mode 100644 index 0000000..0214912 Binary files /dev/null and b/bin/org/apache/commons/net/DefaultSocketFactory.class differ diff --git a/bin/org/apache/commons/net/MalformedServerReplyException.class b/bin/org/apache/commons/net/MalformedServerReplyException.class new file mode 100644 index 0000000..1029ea6 Binary files /dev/null and b/bin/org/apache/commons/net/MalformedServerReplyException.class differ diff --git a/bin/org/apache/commons/net/PrintCommandListener.class b/bin/org/apache/commons/net/PrintCommandListener.class new file mode 100644 index 0000000..14175f9 Binary files /dev/null and b/bin/org/apache/commons/net/PrintCommandListener.class differ diff --git a/bin/org/apache/commons/net/ProtocolCommandEvent.class b/bin/org/apache/commons/net/ProtocolCommandEvent.class new file mode 100644 index 0000000..348bc9b Binary files /dev/null and b/bin/org/apache/commons/net/ProtocolCommandEvent.class differ diff --git a/bin/org/apache/commons/net/ProtocolCommandListener.class b/bin/org/apache/commons/net/ProtocolCommandListener.class new file mode 100644 index 0000000..febe5f7 Binary files /dev/null and b/bin/org/apache/commons/net/ProtocolCommandListener.class differ diff --git a/bin/org/apache/commons/net/ProtocolCommandSupport.class b/bin/org/apache/commons/net/ProtocolCommandSupport.class new file mode 100644 index 0000000..b5e8190 Binary files /dev/null and b/bin/org/apache/commons/net/ProtocolCommandSupport.class differ diff --git a/bin/org/apache/commons/net/SocketClient.class b/bin/org/apache/commons/net/SocketClient.class new file mode 100644 index 0000000..cdb687b Binary files /dev/null and b/bin/org/apache/commons/net/SocketClient.class differ diff --git a/bin/org/apache/commons/net/ftp/Configurable.class b/bin/org/apache/commons/net/ftp/Configurable.class new file mode 100644 index 0000000..ccf792a Binary files /dev/null and b/bin/org/apache/commons/net/ftp/Configurable.class differ diff --git a/bin/org/apache/commons/net/ftp/FTP.class b/bin/org/apache/commons/net/ftp/FTP.class new file mode 100644 index 0000000..8da8080 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTP.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPClient.class b/bin/org/apache/commons/net/ftp/FTPClient.class new file mode 100644 index 0000000..3d5c9b4 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPClient.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPClientConfig.class b/bin/org/apache/commons/net/ftp/FTPClientConfig.class new file mode 100644 index 0000000..2d37625 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPClientConfig.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPCommand.class b/bin/org/apache/commons/net/ftp/FTPCommand.class new file mode 100644 index 0000000..1ab8bdc Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPCommand.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPConnectionClosedException.class b/bin/org/apache/commons/net/ftp/FTPConnectionClosedException.class new file mode 100644 index 0000000..3b32606 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPConnectionClosedException.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPFile.class b/bin/org/apache/commons/net/ftp/FTPFile.class new file mode 100644 index 0000000..1d34b1b Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPFile.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPFileEntryParser.class b/bin/org/apache/commons/net/ftp/FTPFileEntryParser.class new file mode 100644 index 0000000..2b7ae2e Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPFileEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class b/bin/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class new file mode 100644 index 0000000..b85c462 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPListParseEngine.class b/bin/org/apache/commons/net/ftp/FTPListParseEngine.class new file mode 100644 index 0000000..ac3e453 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPListParseEngine.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPReply.class b/bin/org/apache/commons/net/ftp/FTPReply.class new file mode 100644 index 0000000..3e3be4a Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPReply.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPSClient.class b/bin/org/apache/commons/net/ftp/FTPSClient.class new file mode 100644 index 0000000..27b495e Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPSClient.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPSCommand.class b/bin/org/apache/commons/net/ftp/FTPSCommand.class new file mode 100644 index 0000000..82e168d Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPSCommand.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPSSocketFactory.class b/bin/org/apache/commons/net/ftp/FTPSSocketFactory.class new file mode 100644 index 0000000..3ad4aa5 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPSSocketFactory.class differ diff --git a/bin/org/apache/commons/net/ftp/FTPSTrustManager.class b/bin/org/apache/commons/net/ftp/FTPSTrustManager.class new file mode 100644 index 0000000..3e62487 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/FTPSTrustManager.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class b/bin/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class new file mode 100644 index 0000000..2bc05ed Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class b/bin/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class new file mode 100644 index 0000000..13da0a8 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class b/bin/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class new file mode 100644 index 0000000..6449876 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.class new file mode 100644 index 0000000..9b94242 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class b/bin/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class new file mode 100644 index 0000000..9eb116e Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/FTPTimestampParser.class b/bin/org/apache/commons/net/ftp/parser/FTPTimestampParser.class new file mode 100644 index 0000000..25ecea6 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/FTPTimestampParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class b/bin/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class new file mode 100644 index 0000000..ff3bd50 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class new file mode 100644 index 0000000..4ccb95c Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class new file mode 100644 index 0000000..b422f44 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class new file mode 100644 index 0000000..33a7d50 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class new file mode 100644 index 0000000..10fc1bb Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class new file mode 100644 index 0000000..1fa8d0e Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/ParserInitializationException.class b/bin/org/apache/commons/net/ftp/parser/ParserInitializationException.class new file mode 100644 index 0000000..2608c80 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/ParserInitializationException.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class b/bin/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class new file mode 100644 index 0000000..6908382 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class new file mode 100644 index 0000000..c274ea7 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class new file mode 100644 index 0000000..fa5c9ba Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class b/bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class new file mode 100644 index 0000000..968e617 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class differ diff --git a/bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class b/bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class new file mode 100644 index 0000000..a58fdd2 Binary files /dev/null and b/bin/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class differ diff --git a/bin/org/apache/commons/net/io/CopyStreamAdapter.class b/bin/org/apache/commons/net/io/CopyStreamAdapter.class new file mode 100644 index 0000000..1f71724 Binary files /dev/null and b/bin/org/apache/commons/net/io/CopyStreamAdapter.class differ diff --git a/bin/org/apache/commons/net/io/CopyStreamEvent.class b/bin/org/apache/commons/net/io/CopyStreamEvent.class new file mode 100644 index 0000000..94a6a08 Binary files /dev/null and b/bin/org/apache/commons/net/io/CopyStreamEvent.class differ diff --git a/bin/org/apache/commons/net/io/CopyStreamException.class b/bin/org/apache/commons/net/io/CopyStreamException.class new file mode 100644 index 0000000..a85cd86 Binary files /dev/null and b/bin/org/apache/commons/net/io/CopyStreamException.class differ diff --git a/bin/org/apache/commons/net/io/CopyStreamListener.class b/bin/org/apache/commons/net/io/CopyStreamListener.class new file mode 100644 index 0000000..319b76b Binary files /dev/null and b/bin/org/apache/commons/net/io/CopyStreamListener.class differ diff --git a/bin/org/apache/commons/net/io/DotTerminatedMessageReader.class b/bin/org/apache/commons/net/io/DotTerminatedMessageReader.class new file mode 100644 index 0000000..1e67304 Binary files /dev/null and b/bin/org/apache/commons/net/io/DotTerminatedMessageReader.class differ diff --git a/bin/org/apache/commons/net/io/DotTerminatedMessageWriter.class b/bin/org/apache/commons/net/io/DotTerminatedMessageWriter.class new file mode 100644 index 0000000..124e517 Binary files /dev/null and b/bin/org/apache/commons/net/io/DotTerminatedMessageWriter.class differ diff --git a/bin/org/apache/commons/net/io/FromNetASCIIInputStream.class b/bin/org/apache/commons/net/io/FromNetASCIIInputStream.class new file mode 100644 index 0000000..288992a Binary files /dev/null and b/bin/org/apache/commons/net/io/FromNetASCIIInputStream.class differ diff --git a/bin/org/apache/commons/net/io/FromNetASCIIOutputStream.class b/bin/org/apache/commons/net/io/FromNetASCIIOutputStream.class new file mode 100644 index 0000000..b8524d5 Binary files /dev/null and b/bin/org/apache/commons/net/io/FromNetASCIIOutputStream.class differ diff --git a/bin/org/apache/commons/net/io/SocketInputStream.class b/bin/org/apache/commons/net/io/SocketInputStream.class new file mode 100644 index 0000000..6c215b4 Binary files /dev/null and b/bin/org/apache/commons/net/io/SocketInputStream.class differ diff --git a/bin/org/apache/commons/net/io/SocketOutputStream.class b/bin/org/apache/commons/net/io/SocketOutputStream.class new file mode 100644 index 0000000..b83a385 Binary files /dev/null and b/bin/org/apache/commons/net/io/SocketOutputStream.class differ diff --git a/bin/org/apache/commons/net/io/ToNetASCIIInputStream.class b/bin/org/apache/commons/net/io/ToNetASCIIInputStream.class new file mode 100644 index 0000000..13bf861 Binary files /dev/null and b/bin/org/apache/commons/net/io/ToNetASCIIInputStream.class differ diff --git a/bin/org/apache/commons/net/io/ToNetASCIIOutputStream.class b/bin/org/apache/commons/net/io/ToNetASCIIOutputStream.class new file mode 100644 index 0000000..bee2c00 Binary files /dev/null and b/bin/org/apache/commons/net/io/ToNetASCIIOutputStream.class differ diff --git a/bin/org/apache/commons/net/io/Util.class b/bin/org/apache/commons/net/io/Util.class new file mode 100644 index 0000000..ebfa4f1 Binary files /dev/null and b/bin/org/apache/commons/net/io/Util.class differ diff --git a/bin/org/apache/commons/net/util/ListenerList.class b/bin/org/apache/commons/net/util/ListenerList.class new file mode 100644 index 0000000..835ef3e Binary files /dev/null and b/bin/org/apache/commons/net/util/ListenerList.class differ diff --git a/bin/org/apache/commons/net/util/SubnetUtils$SubnetInfo.class b/bin/org/apache/commons/net/util/SubnetUtils$SubnetInfo.class new file mode 100644 index 0000000..f064e4f Binary files /dev/null and b/bin/org/apache/commons/net/util/SubnetUtils$SubnetInfo.class differ diff --git a/bin/org/apache/commons/net/util/SubnetUtils.class b/bin/org/apache/commons/net/util/SubnetUtils.class new file mode 100644 index 0000000..8722881 Binary files /dev/null and b/bin/org/apache/commons/net/util/SubnetUtils.class differ diff --git a/bin/resources.ap_ b/bin/resources.ap_ new file mode 100644 index 0000000..fc4666a Binary files /dev/null and b/bin/resources.ap_ differ diff --git a/default.properties b/default.properties new file mode 100644 index 0000000..9d135cb --- /dev/null +++ b/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/gen/com/lc8n/blauploader/R.java b/gen/com/lc8n/blauploader/R.java new file mode 100644 index 0000000..4de5f2b --- /dev/null +++ b/gen/com/lc8n/blauploader/R.java @@ -0,0 +1,27 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package com.lc8n.blauploader; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class id { + public static final int ProgressBar01=0x7f050000; + } + public static final class layout { + public static final int filerow=0x7f030000; + public static final int main=0x7f030001; + } + public static final class string { + public static final int app_name=0x7f040001; + public static final int hello=0x7f040000; + } +} diff --git a/org/apache/commons/net/DatagramSocketClient.java b/org/apache/commons/net/DatagramSocketClient.java new file mode 100644 index 0000000..9199704 --- /dev/null +++ b/org/apache/commons/net/DatagramSocketClient.java @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/*** + * The DatagramSocketClient provides the basic operations that are required + * of client objects accessing datagram sockets. It is meant to be + * subclassed to avoid having to rewrite the same code over and over again + * to open a socket, close a socket, set timeouts, etc. Of special note + * is the {@link #setDatagramSocketFactory setDatagramSocketFactory } + * method, which allows you to control the type of DatagramSocket the + * DatagramSocketClient creates for network communications. This is + * especially useful for adding things like proxy support as well as better + * support for applets. For + * example, you could create a + * {@link org.apache.commons.net.DatagramSocketFactory} + * that + * requests browser security capabilities before creating a socket. + * All classes derived from DatagramSocketClient should use the + * {@link #_socketFactory_ _socketFactory_ } member variable to + * create DatagramSocket instances rather than instantiating + * them by directly invoking a constructor. By honoring this contract + * you guarantee that a user will always be able to provide his own + * Socket implementations by substituting his own SocketFactory. + *

+ *

+ * @author Daniel F. Savarese + * @see DatagramSocketFactory + ***/ + +public abstract class DatagramSocketClient +{ + /*** + * The default DatagramSocketFactory shared by all DatagramSocketClient + * instances. + ***/ + private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY = + new DefaultDatagramSocketFactory(); + + /*** The timeout to use after opening a socket. ***/ + protected int _timeout_; + + /*** The datagram socket used for the connection. ***/ + protected DatagramSocket _socket_; + + /*** + * A status variable indicating if the client's socket is currently open. + ***/ + protected boolean _isOpen_; + + /*** The datagram socket's DatagramSocketFactory. ***/ + protected DatagramSocketFactory _socketFactory_; + + /*** + * Default constructor for DatagramSocketClient. Initializes + * _socket_ to null, _timeout_ to 0, and _isOpen_ to false. + ***/ + public DatagramSocketClient() + { + _socket_ = null; + _timeout_ = 0; + _isOpen_ = false; + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + } + + + /*** + * Opens a DatagramSocket on the local host at the first available port. + * Also sets the timeout on the socket to the default timeout set + * by {@link #setDefaultTimeout setDefaultTimeout() }. + *

+ * _isOpen_ is set to true after calling this method and _socket_ + * is set to the newly opened socket. + *

+ * @exception SocketException If the socket could not be opened or the + * timeout could not be set. + ***/ + public void open() throws SocketException + { + _socket_ = _socketFactory_.createDatagramSocket(); + _socket_.setSoTimeout(_timeout_); + _isOpen_ = true; + } + + + /*** + * Opens a DatagramSocket on the local host at a specified port. + * Also sets the timeout on the socket to the default timeout set + * by {@link #setDefaultTimeout setDefaultTimeout() }. + *

+ * _isOpen_ is set to true after calling this method and _socket_ + * is set to the newly opened socket. + *

+ * @param port The port to use for the socket. + * @exception SocketException If the socket could not be opened or the + * timeout could not be set. + ***/ + public void open(int port) throws SocketException + { + _socket_ = _socketFactory_.createDatagramSocket(port); + _socket_.setSoTimeout(_timeout_); + _isOpen_ = true; + } + + + /*** + * Opens a DatagramSocket at the specified address on the local host + * at a specified port. + * Also sets the timeout on the socket to the default timeout set + * by {@link #setDefaultTimeout setDefaultTimeout() }. + *

+ * _isOpen_ is set to true after calling this method and _socket_ + * is set to the newly opened socket. + *

+ * @param port The port to use for the socket. + * @param laddr The local address to use. + * @exception SocketException If the socket could not be opened or the + * timeout could not be set. + ***/ + public void open(int port, InetAddress laddr) throws SocketException + { + _socket_ = _socketFactory_.createDatagramSocket(port, laddr); + _socket_.setSoTimeout(_timeout_); + _isOpen_ = true; + } + + + + /*** + * Closes the DatagramSocket used for the connection. + * You should call this method after you've finished using the class + * instance and also before you call {@link #open open() } + * again. _isOpen_ is set to false and _socket_ is set to null. + * If you call this method when the client socket is not open, + * a NullPointerException is thrown. + ***/ + public void close() + { + _socket_.close(); + _socket_ = null; + _isOpen_ = false; + } + + + /*** + * Returns true if the client has a currently open socket. + *

+ * @return True if the client has a curerntly open socket, false otherwise. + ***/ + public boolean isOpen() + { + return _isOpen_; + } + + + /*** + * Set the default timeout in milliseconds to use when opening a socket. + * After a call to open, the timeout for the socket is set using this value. + * This method should be used prior to a call to {@link #open open()} + * and should not be confused with {@link #setSoTimeout setSoTimeout()} + * which operates on the currently open socket. _timeout_ contains + * the new timeout value. + *

+ * @param timeout The timeout in milliseconds to use for the datagram socket + * connection. + ***/ + public void setDefaultTimeout(int timeout) + { + _timeout_ = timeout; + } + + + /*** + * Returns the default timeout in milliseconds that is used when + * opening a socket. + *

+ * @return The default timeout in milliseconds that is used when + * opening a socket. + ***/ + public int getDefaultTimeout() + { + return _timeout_; + } + + + /*** + * Set the timeout in milliseconds of a currently open connection. + * Only call this method after a connection has been opened + * by {@link #open open()}. + *

+ * @param timeout The timeout in milliseconds to use for the currently + * open datagram socket connection. + ***/ + public void setSoTimeout(int timeout) throws SocketException + { + _socket_.setSoTimeout(timeout); + } + + + /*** + * Returns the timeout in milliseconds of the currently opened socket. + * If you call this method when the client socket is not open, + * a NullPointerException is thrown. + *

+ * @return The timeout in milliseconds of the currently opened socket. + ***/ + public int getSoTimeout() throws SocketException + { + return _socket_.getSoTimeout(); + } + + + /*** + * Returns the port number of the open socket on the local host used + * for the connection. If you call this method when the client socket + * is not open, a NullPointerException is thrown. + *

+ * @return The port number of the open socket on the local host used + * for the connection. + ***/ + public int getLocalPort() + { + return _socket_.getLocalPort(); + } + + + /*** + * Returns the local address to which the client's socket is bound. + * If you call this method when the client socket is not open, a + * NullPointerException is thrown. + *

+ * @return The local address to which the client's socket is bound. + ***/ + public InetAddress getLocalAddress() + { + return _socket_.getLocalAddress(); + } + + + /*** + * Sets the DatagramSocketFactory used by the DatagramSocketClient + * to open DatagramSockets. If the factory value is null, then a default + * factory is used (only do this to reset the factory after having + * previously altered it). + *

+ * @param factory The new DatagramSocketFactory the DatagramSocketClient + * should use. + ***/ + public void setDatagramSocketFactory(DatagramSocketFactory factory) + { + if (factory == null) + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + else + _socketFactory_ = factory; + } +} diff --git a/org/apache/commons/net/DatagramSocketFactory.java b/org/apache/commons/net/DatagramSocketFactory.java new file mode 100644 index 0000000..c152eb2 --- /dev/null +++ b/org/apache/commons/net/DatagramSocketFactory.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/*** + * The DatagramSocketFactory interface provides a means for the + * programmer to control the creation of datagram sockets and + * provide his own DatagramSocket implementations for use by all + * classes derived from + * {@link org.apache.commons.net.DatagramSocketClient} + * . + * This allows you to provide your own DatagramSocket implementations and + * to perform security checks or browser capability requests before + * creating a DatagramSocket. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public interface DatagramSocketFactory +{ + + /*** + * Creates a DatagramSocket on the local host at the first available port. + *

+ * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket() throws SocketException; + + /*** + * Creates a DatagramSocket on the local host at a specified port. + *

+ * @param port The port to use for the socket. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port) throws SocketException; + + /*** + * Creates a DatagramSocket at the specified address on the local host + * at a specified port. + *

+ * @param port The port to use for the socket. + * @param laddr The local address to use. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port, InetAddress laddr) + throws SocketException; +} diff --git a/org/apache/commons/net/DefaultDatagramSocketFactory.java b/org/apache/commons/net/DefaultDatagramSocketFactory.java new file mode 100644 index 0000000..3983fcb --- /dev/null +++ b/org/apache/commons/net/DefaultDatagramSocketFactory.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/*** + * DefaultDatagramSocketFactory implements the DatagramSocketFactory + * interface by simply wrapping the java.net.DatagramSocket + * constructors. It is the default DatagramSocketFactory used by + * {@link org.apache.commons.net.DatagramSocketClient} + * implementations. + *

+ *

+ * @author Daniel F. Savarese + * @see DatagramSocketFactory + * @see DatagramSocketClient + * @see DatagramSocketClient#setDatagramSocketFactory + ***/ + +public class DefaultDatagramSocketFactory implements DatagramSocketFactory +{ + + /*** + * Creates a DatagramSocket on the local host at the first available port. + *

+ * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket() throws SocketException + { + return new DatagramSocket(); + } + + /*** + * Creates a DatagramSocket on the local host at a specified port. + *

+ * @param port The port to use for the socket. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port) throws SocketException + { + return new DatagramSocket(port); + } + + /*** + * Creates a DatagramSocket at the specified address on the local host + * at a specified port. + *

+ * @param port The port to use for the socket. + * @param laddr The local address to use. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port, InetAddress laddr) + throws SocketException + { + return new DatagramSocket(port, laddr); + } +} diff --git a/org/apache/commons/net/DefaultSocketFactory.java b/org/apache/commons/net/DefaultSocketFactory.java new file mode 100644 index 0000000..e809f84 --- /dev/null +++ b/org/apache/commons/net/DefaultSocketFactory.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.SocketFactory; + +/*** + * DefaultSocketFactory implements the SocketFactory interface by + * simply wrapping the java.net.Socket and java.net.ServerSocket + * constructors. It is the default SocketFactory used by + * {@link org.apache.commons.net.SocketClient} + * implementations. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketFactory + * @see SocketClient + * @see SocketClient#setSocketFactory + ***/ + +public class DefaultSocketFactory extends SocketFactory +{ + + /*** + * Creates a Socket connected to the given host and port. + *

+ * @param host The hostname to connect to. + * @param port The port to connect to. + * @return A Socket connected to the given host and port. + * @exception UnknownHostException If the hostname cannot be resolved. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(String host, int port) + throws UnknownHostException, IOException + { + return new Socket(host, port); + } + + /*** + * Creates a Socket connected to the given host and port. + *

+ * @param address The address of the host to connect to. + * @param port The port to connect to. + * @return A Socket connected to the given host and port. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(InetAddress address, int port) + throws IOException + { + return new Socket(address, port); + } + + /*** + * Creates a Socket connected to the given host and port and + * originating from the specified local address and port. + *

+ * @param host The hostname to connect to. + * @param port The port to connect to. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @return A Socket connected to the given host and port. + * @exception UnknownHostException If the hostname cannot be resolved. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(String host, int port, + InetAddress localAddr, int localPort) + throws UnknownHostException, IOException + { + return new Socket(host, port, localAddr, localPort); + } + + /*** + * Creates a Socket connected to the given host and port and + * originating from the specified local address and port. + *

+ * @param address The address of the host to connect to. + * @param port The port to connect to. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @return A Socket connected to the given host and port. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(InetAddress address, int port, + InetAddress localAddr, int localPort) + throws IOException + { + return new Socket(address, port, localAddr, localPort); + } + + /*** + * Creates a ServerSocket bound to a specified port. A port + * of 0 will create the ServerSocket on a system-determined free port. + *

+ * @param port The port on which to listen, or 0 to use any free port. + * @return A ServerSocket that will listen on a specified port. + * @exception IOException If an I/O error occurs while creating + * the ServerSocket. + ***/ + public ServerSocket createServerSocket(int port) throws IOException + { + return new ServerSocket(port); + } + + /*** + * Creates a ServerSocket bound to a specified port with a given + * maximum queue length for incoming connections. A port of 0 will + * create the ServerSocket on a system-determined free port. + *

+ * @param port The port on which to listen, or 0 to use any free port. + * @param backlog The maximum length of the queue for incoming connections. + * @return A ServerSocket that will listen on a specified port. + * @exception IOException If an I/O error occurs while creating + * the ServerSocket. + ***/ + public ServerSocket createServerSocket(int port, int backlog) + throws IOException + { + return new ServerSocket(port, backlog); + } + + /*** + * Creates a ServerSocket bound to a specified port on a given local + * address with a given maximum queue length for incoming connections. + * A port of 0 will + * create the ServerSocket on a system-determined free port. + *

+ * @param port The port on which to listen, or 0 to use any free port. + * @param backlog The maximum length of the queue for incoming connections. + * @param bindAddr The local address to which the ServerSocket should bind. + * @return A ServerSocket that will listen on a specified port. + * @exception IOException If an I/O error occurs while creating + * the ServerSocket. + ***/ + public ServerSocket createServerSocket(int port, int backlog, + InetAddress bindAddr) + throws IOException + { + return new ServerSocket(port, backlog, bindAddr); + } +} diff --git a/org/apache/commons/net/MalformedServerReplyException.class b/org/apache/commons/net/MalformedServerReplyException.class new file mode 100644 index 0000000..6b04dd8 Binary files /dev/null and b/org/apache/commons/net/MalformedServerReplyException.class differ diff --git a/org/apache/commons/net/MalformedServerReplyException.java b/org/apache/commons/net/MalformedServerReplyException.java new file mode 100644 index 0000000..3cad5f0 --- /dev/null +++ b/org/apache/commons/net/MalformedServerReplyException.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.IOException; + +/*** + * This exception is used to indicate that the reply from a server + * could not be interpreted. Most of the NetComponents classes attempt + * to be as lenient as possible when receiving server replies. Many + * server implementations deviate from IETF protocol specifications, making + * it necessary to be as flexible as possible. However, there will be + * certain situations where it is not possible to continue an operation + * because the server reply could not be interpreted in a meaningful manner. + * In these cases, a MalformedServerReplyException should be thrown. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public class MalformedServerReplyException extends IOException +{ + + /*** Constructs a MalformedServerReplyException with no message ***/ + public MalformedServerReplyException() + { + super(); + } + + /*** + * Constructs a MalformedServerReplyException with a specified message. + *

+ * @param message The message explaining the reason for the exception. + ***/ + public MalformedServerReplyException(String message) + { + super(message); + } + +} diff --git a/org/apache/commons/net/PrintCommandListener.java b/org/apache/commons/net/PrintCommandListener.java new file mode 100644 index 0000000..d8e7a68 --- /dev/null +++ b/org/apache/commons/net/PrintCommandListener.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.PrintWriter; +import org.apache.commons.net.ProtocolCommandEvent; +import org.apache.commons.net.ProtocolCommandListener; + +/*** + * This is a support class for some of the example programs. It is + * a sample implementation of the ProtocolCommandListener interface + * which just prints out to a specified stream all command/reply traffic. + *

+ * + * @since 2.0 + ***/ + +public class PrintCommandListener implements ProtocolCommandListener +{ + private PrintWriter __writer; + + public PrintCommandListener(PrintWriter writer) + { + __writer = writer; + } + + public void protocolCommandSent(ProtocolCommandEvent event) + { + __writer.print(event.getMessage()); + __writer.flush(); + } + + public void protocolReplyReceived(ProtocolCommandEvent event) + { + __writer.print(event.getMessage()); + __writer.flush(); + } +} + diff --git a/org/apache/commons/net/ProtocolCommandEvent.class b/org/apache/commons/net/ProtocolCommandEvent.class new file mode 100644 index 0000000..e558b69 Binary files /dev/null and b/org/apache/commons/net/ProtocolCommandEvent.class differ diff --git a/org/apache/commons/net/ProtocolCommandEvent.java b/org/apache/commons/net/ProtocolCommandEvent.java new file mode 100644 index 0000000..8977c03 --- /dev/null +++ b/org/apache/commons/net/ProtocolCommandEvent.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; +import java.util.EventObject; + +/*** + * There exists a large class of IETF protocols that work by sending an + * ASCII text command and arguments to a server, and then receiving an + * ASCII text reply. For debugging and other purposes, it is extremely + * useful to log or keep track of the contents of the protocol messages. + * The ProtocolCommandEvent class coupled with the + * {@link org.apache.commons.net.ProtocolCommandListener} + * interface facilitate this process. + *

+ *

+ * @see ProtocolCommandListener + * @see ProtocolCommandSupport + * @author Daniel F. Savarese + ***/ + +public class ProtocolCommandEvent extends EventObject +{ + private int __replyCode; + private boolean __isCommand; + private String __message, __command; + + /*** + * Creates a ProtocolCommandEvent signalling a command was sent to + * the server. ProtocolCommandEvents created with this constructor + * should only be sent after a command has been sent, but before the + * reply has been received. + *

+ * @param source The source of the event. + * @param command The string representation of the command type sent, not + * including the arguments (e.g., "STAT" or "GET"). + * @param message The entire command string verbatim as sent to the server, + * including all arguments. + ***/ + public ProtocolCommandEvent(Object source, String command, String message) + { + super(source); + __replyCode = 0; + __message = message; + __isCommand = true; + __command = command; + } + + + /*** + * Creates a ProtocolCommandEvent signalling a reply to a command was + * received. ProtocolCommandEvents created with this constructor + * should only be sent after a complete command reply has been received + * fromt a server. + *

+ * @param source The source of the event. + * @param replyCode The integer code indicating the natureof the reply. + * This will be the protocol integer value for protocols + * that use integer reply codes, or the reply class constant + * corresponding to the reply for protocols like POP3 that use + * strings like OK rather than integer codes (i.e., POP3Repy.OK). + * @param message The entire reply as received from the server. + ***/ + public ProtocolCommandEvent(Object source, int replyCode, String message) + { + super(source); + __replyCode = replyCode; + __message = message; + __isCommand = false; + __command = null; + } + + /*** + * Returns the string representation of the command type sent (e.g., "STAT" + * or "GET"). If the ProtocolCommandEvent is a reply event, then null + * is returned. + *

+ * @return The string representation of the command type sent, or null + * if this is a reply event. + ***/ + public String getCommand() + { + return __command; + } + + + /*** + * Returns the reply code of the received server reply. Undefined if + * this is not a reply event. + *

+ * @return The reply code of the received server reply. Undefined if + * not a reply event. + ***/ + public int getReplyCode() + { + return __replyCode; + } + + /*** + * Returns true if the ProtocolCommandEvent was generated as a result + * of sending a command. + *

+ * @return true If the ProtocolCommandEvent was generated as a result + * of sending a command. False otherwise. + ***/ + public boolean isCommand() + { + return __isCommand; + } + + /*** + * Returns true if the ProtocolCommandEvent was generated as a result + * of receiving a reply. + *

+ * @return true If the ProtocolCommandEvent was generated as a result + * of receiving a reply. False otherwise. + ***/ + public boolean isReply() + { + return !isCommand(); + } + + /*** + * Returns the entire message sent to or received from the server. + *

+ * @return The entire message sent to or received from the server. + ***/ + public String getMessage() + { + return __message; + } +} diff --git a/org/apache/commons/net/ProtocolCommandListener.class b/org/apache/commons/net/ProtocolCommandListener.class new file mode 100644 index 0000000..54d6a46 Binary files /dev/null and b/org/apache/commons/net/ProtocolCommandListener.class differ diff --git a/org/apache/commons/net/ProtocolCommandListener.java b/org/apache/commons/net/ProtocolCommandListener.java new file mode 100644 index 0000000..8089926 --- /dev/null +++ b/org/apache/commons/net/ProtocolCommandListener.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; +import java.util.EventListener; + +/*** + * There exists a large class of IETF protocols that work by sending an + * ASCII text command and arguments to a server, and then receiving an + * ASCII text reply. For debugging and other purposes, it is extremely + * useful to log or keep track of the contents of the protocol messages. + * The ProtocolCommandListener interface coupled with the + * {@link ProtocolCommandEvent} class facilitate this process. + *

+ * To receive ProtocolCommandEvents, you merely implement the + * ProtocolCommandListener interface and register the class as a listener + * with a ProtocolCommandEvent source such as + * {@link org.apache.commons.net.ftp.FTPClient}. + *

+ *

+ * @see ProtocolCommandEvent + * @see ProtocolCommandSupport + * @author Daniel F. Savarese + ***/ + +public interface ProtocolCommandListener extends EventListener +{ + + /*** + * This method is invoked by a ProtocolCommandEvent source after + * sending a protocol command to a server. + *

+ * @param event The ProtocolCommandEvent fired. + ***/ + public void protocolCommandSent(ProtocolCommandEvent event); + + /*** + * This method is invoked by a ProtocolCommandEvent source after + * receiving a reply from a server. + *

+ * @param event The ProtocolCommandEvent fired. + ***/ + public void protocolReplyReceived(ProtocolCommandEvent event); + +} diff --git a/org/apache/commons/net/ProtocolCommandSupport.class b/org/apache/commons/net/ProtocolCommandSupport.class new file mode 100644 index 0000000..70ee4eb Binary files /dev/null and b/org/apache/commons/net/ProtocolCommandSupport.class differ diff --git a/org/apache/commons/net/ProtocolCommandSupport.java b/org/apache/commons/net/ProtocolCommandSupport.java new file mode 100644 index 0000000..1a51fb6 --- /dev/null +++ b/org/apache/commons/net/ProtocolCommandSupport.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.Serializable; +import java.util.EventListener; + +import org.apache.commons.net.util.ListenerList; + +/*** + * ProtocolCommandSupport is a convenience class for managing a list of + * ProtocolCommandListeners and firing ProtocolCommandEvents. You can + * simply delegate ProtocolCommandEvent firing and listener + * registering/unregistering tasks to this class. + *

+ *

+ * @see ProtocolCommandEvent + * @see ProtocolCommandListener + * @author Daniel F. Savarese + ***/ + +public class ProtocolCommandSupport implements Serializable +{ + private Object __source; + private ListenerList __listeners; + + /*** + * Creates a ProtocolCommandSupport instant using the indicated source + * as the source of fired ProtocolCommandEvents. + *

+ * @param source The source to use for all generated ProtocolCommandEvents. + ***/ + public ProtocolCommandSupport(Object source) + { + __listeners = new ListenerList(); + __source = source; + } + + + /*** + * Fires a ProtocolCommandEvent signalling the sending of a command to all + * registered listeners, invoking their + * {@link org.apache.commons.net.ProtocolCommandListener#protocolCommandSent protocolCommandSent() } + * methods. + *

+ * @param command The string representation of the command type sent, not + * including the arguments (e.g., "STAT" or "GET"). + * @param message The entire command string verbatim as sent to the server, + * including all arguments. + ***/ + public void fireCommandSent(String command, String message) + { + ProtocolCommandEvent event; + + event = new ProtocolCommandEvent(__source, command, message); + + for (EventListener listener : __listeners) + { + ((ProtocolCommandListener)listener).protocolCommandSent(event); + } + } + + /*** + * Fires a ProtocolCommandEvent signalling the reception of a command reply + * to all registered listeners, invoking their + * {@link org.apache.commons.net.ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() } + * methods. + *

+ * @param replyCode The integer code indicating the natureof the reply. + * This will be the protocol integer value for protocols + * that use integer reply codes, or the reply class constant + * corresponding to the reply for protocols like POP3 that use + * strings like OK rather than integer codes (i.e., POP3Repy.OK). + * @param message The entire reply as received from the server. + ***/ + public void fireReplyReceived(int replyCode, String message) + { + ProtocolCommandEvent event; + event = new ProtocolCommandEvent(__source, replyCode, message); + + for (EventListener listener : __listeners) + { + ((ProtocolCommandListener)listener).protocolReplyReceived(event); + } + } + + /*** + * Adds a ProtocolCommandListener. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + __listeners.addListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandListener(ProtocolCommandListener listener) + { + __listeners.removeListener(listener); + } + + + /*** + * Returns the number of ProtocolCommandListeners currently registered. + *

+ * @return The number of ProtocolCommandListeners currently registered. + ***/ + public int getListenerCount() + { + return __listeners.getListenerCount(); + } + +} + diff --git a/org/apache/commons/net/SocketClient.class b/org/apache/commons/net/SocketClient.class new file mode 100644 index 0000000..216f590 Binary files /dev/null and b/org/apache/commons/net/SocketClient.class differ diff --git a/org/apache/commons/net/SocketClient.java b/org/apache/commons/net/SocketClient.java new file mode 100644 index 0000000..a5a8ead --- /dev/null +++ b/org/apache/commons/net/SocketClient.java @@ -0,0 +1,586 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; + +import javax.net.ServerSocketFactory; +import javax.net.SocketFactory; + + +/** + * The SocketClient provides the basic operations that are required of + * client objects accessing sockets. It is meant to be + * subclassed to avoid having to rewrite the same code over and over again + * to open a socket, close a socket, set timeouts, etc. Of special note + * is the {@link #setSocketFactory setSocketFactory } + * method, which allows you to control the type of Socket the SocketClient + * creates for initiating network connections. This is especially useful + * for adding SSL or proxy support as well as better support for applets. For + * example, you could create a + * {@link org.apache.commons.net.SocketFactory} that + * requests browser security capabilities before creating a socket. + * All classes derived from SocketClient should use the + * {@link #_socketFactory_ _socketFactory_ } member variable to + * create Socket and ServerSocket instances rather than instanting + * them by directly invoking a constructor. By honoring this contract + * you guarantee that a user will always be able to provide his own + * Socket implementations by substituting his own SocketFactory. + * @author Daniel F. Savarese + * @see SocketFactory + */ +public abstract class SocketClient +{ + /** + * The end of line character sequence used by most IETF protocols. That + * is a carriage return followed by a newline: "\r\n" + */ + public static final String NETASCII_EOL = "\r\n"; + + /** The default SocketFactory shared by all SocketClient instances. */ + private static final SocketFactory __DEFAULT_SOCKET_FACTORY = + SocketFactory.getDefault(); + + private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = + ServerSocketFactory.getDefault(); + + /** The timeout to use after opening a socket. */ + protected int _timeout_; + + /** The socket used for the connection. */ + protected Socket _socket_; + + /** The default port the client should connect to. */ + protected int _defaultPort_; + + /** The socket's InputStream. */ + protected InputStream _input_; + + /** The socket's OutputStream. */ + protected OutputStream _output_; + + /** The socket's SocketFactory. */ + protected SocketFactory _socketFactory_; + + /** The socket's ServerSocket Factory. */ + protected ServerSocketFactory _serverSocketFactory_; + + /** The socket's connect timeout (0 = infinite timeout) */ + private static final int DEFAULT_CONNECT_TIMEOUT = 0; + protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; + + /** + * Default constructor for SocketClient. Initializes + * _socket_ to null, _timeout_ to 0, _defaultPort to 0, + * _isConnected_ to false, and _socketFactory_ to a shared instance of + * {@link org.apache.commons.net.DefaultSocketFactory}. + */ + public SocketClient() + { + _socket_ = null; + _input_ = null; + _output_ = null; + _timeout_ = 0; + _defaultPort_ = 0; + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; + } + + + /** + * Because there are so many connect() methods, the _connectAction_() + * method is provided as a means of performing some action immediately + * after establishing a connection, rather than reimplementing all + * of the connect() methods. The last action performed by every + * connect() method after opening a socket is to call this method. + *

+ * This method sets the timeout on the just opened socket to the default + * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, + * sets _input_ and _output_ to the socket's InputStream and OutputStream + * respectively, and sets _isConnected_ to true. + *

+ * Subclasses overriding this method should start by calling + * super._connectAction_() first to ensure the + * initialization of the aforementioned protected variables. + */ + protected void _connectAction_() throws IOException + { + _socket_.setSoTimeout(_timeout_); + _input_ = _socket_.getInputStream(); + _output_ = _socket_.getOutputStream(); + } + + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + */ + public void connect(InetAddress host, int port) + throws SocketException, IOException + { + _socket_ = _socketFactory_.createSocket(); + _socket_.connect(new InetSocketAddress(host, port), connectTimeout); + + _connectAction_(); + } + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + */ + public void connect(String hostname, int port) + throws SocketException, IOException + { + _socket_= _socketFactory_.createSocket(); + _socket_.connect(new InetSocketAddress(hostname, port), connectTimeout); + + _connectAction_(); + } + + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + */ + public void connect(InetAddress host, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException + { + _socket_ = _socketFactory_.createSocket(); + _socket_.bind(new InetSocketAddress(localAddr, localPort)); + _socket_.connect(new InetSocketAddress(host, port), connectTimeout); + + _connectAction_(); + } + + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + */ + public void connect(String hostname, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException + { + _socket_ = + _socketFactory_.createSocket(hostname, port, localAddr, localPort); + _connectAction_(); + } + + + /** + * Opens a Socket connected to a remote host at the current default port + * and originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + */ + public void connect(InetAddress host) throws SocketException, IOException + { + connect(host, _defaultPort_); + } + + + /** + * Opens a Socket connected to a remote host at the current default + * port and originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + */ + public void connect(String hostname) throws SocketException, IOException + { + connect(hostname, _defaultPort_); + } + + + /** + * Disconnects the socket connection. + * You should call this method after you've finished using the class + * instance and also before you call + * {@link #connect connect() } + * again. _isConnected_ is set to false, _socket_ is set to null, + * _input_ is set to null, and _output_ is set to null. + *

+ * @exception IOException If there is an error closing the socket. + */ + public void disconnect() throws IOException + { + if (_socket_ != null) _socket_.close(); + if (_input_ != null) _input_.close(); + if (_output_ != null) _output_.close(); + if (_socket_ != null) _socket_ = null; + _input_ = null; + _output_ = null; + } + + + /** + * Returns true if the client is currently connected to a server. + *

+ * @return True if the client is currently connected to a server, + * false otherwise. + */ + public boolean isConnected() + { + if (_socket_ == null) + return false; + + return _socket_.isConnected(); + } + + + /** + * Sets the default port the SocketClient should connect to when a port + * is not specified. The {@link #_defaultPort_ _defaultPort_ } + * variable stores this value. If never set, the default port is equal + * to zero. + *

+ * @param port The default port to set. + */ + public void setDefaultPort(int port) + { + _defaultPort_ = port; + } + + /** + * Returns the current value of the default port (stored in + * {@link #_defaultPort_ _defaultPort_ }). + *

+ * @return The current value of the default port. + */ + public int getDefaultPort() + { + return _defaultPort_; + } + + + /** + * Set the default timeout in milliseconds to use when opening a socket. + * This value is only used previous to a call to + * {@link #connect connect()} + * and should not be confused with {@link #setSoTimeout setSoTimeout()} + * which operates on an the currently opened socket. _timeout_ contains + * the new timeout value. + *

+ * @param timeout The timeout in milliseconds to use for the socket + * connection. + */ + public void setDefaultTimeout(int timeout) + { + _timeout_ = timeout; + } + + + /** + * Returns the default timeout in milliseconds that is used when + * opening a socket. + *

+ * @return The default timeout in milliseconds that is used when + * opening a socket. + */ + public int getDefaultTimeout() + { + return _timeout_; + } + + + /** + * Set the timeout in milliseconds of a currently open connection. + * Only call this method after a connection has been opened + * by {@link #connect connect()}. + *

+ * @param timeout The timeout in milliseconds to use for the currently + * open socket connection. + * @exception SocketException If the operation fails. + */ + public void setSoTimeout(int timeout) throws SocketException + { + _socket_.setSoTimeout(timeout); + } + + + /** + * Set the underlying socket send buffer size. + *

+ * @param size The size of the buffer in bytes. + * @throws SocketException + * @since 2.0 + */ + public void setSendBufferSize(int size) throws SocketException { + _socket_.setSendBufferSize(size); + } + + + /** + * Sets the underlying socket receive buffer size. + *

+ * @param size The size of the buffer in bytes. + * @throws SocketException + * @since 2.0 + */ + public void setReceiveBufferSize(int size) throws SocketException { + _socket_.setReceiveBufferSize(size); + } + + + /** + * Returns the timeout in milliseconds of the currently opened socket. + *

+ * @return The timeout in milliseconds of the currently opened socket. + * @exception SocketException If the operation fails. + */ + public int getSoTimeout() throws SocketException + { + return _socket_.getSoTimeout(); + } + + /** + * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the + * currently opened socket. + *

+ * @param on True if Nagle's algorithm is to be enabled, false if not. + * @exception SocketException If the operation fails. + */ + public void setTcpNoDelay(boolean on) throws SocketException + { + _socket_.setTcpNoDelay(on); + } + + + /** + * Returns true if Nagle's algorithm is enabled on the currently opened + * socket. + *

+ * @return True if Nagle's algorithm is enabled on the currently opened + * socket, false otherwise. + * @exception SocketException If the operation fails. + */ + public boolean getTcpNoDelay() throws SocketException + { + return _socket_.getTcpNoDelay(); + } + + + /** + * Sets the SO_LINGER timeout on the currently opened socket. + *

+ * @param on True if linger is to be enabled, false if not. + * @param val The linger timeout (in hundredths of a second?) + * @exception SocketException If the operation fails. + */ + public void setSoLinger(boolean on, int val) throws SocketException + { + _socket_.setSoLinger(on, val); + } + + + /** + * Returns the current SO_LINGER timeout of the currently opened socket. + *

+ * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns + * -1. + * @exception SocketException If the operation fails. + */ + public int getSoLinger() throws SocketException + { + return _socket_.getSoLinger(); + } + + + /** + * Returns the port number of the open socket on the local host used + * for the connection. + *

+ * @return The port number of the open socket on the local host used + * for the connection. + */ + public int getLocalPort() + { + return _socket_.getLocalPort(); + } + + + /** + * Returns the local address to which the client's socket is bound. + *

+ * @return The local address to which the client's socket is bound. + */ + public InetAddress getLocalAddress() + { + return _socket_.getLocalAddress(); + } + + /** + * Returns the port number of the remote host to which the client is + * connected. + *

+ * @return The port number of the remote host to which the client is + * connected. + */ + public int getRemotePort() + { + return _socket_.getPort(); + } + + + /** + * @return The remote address to which the client is connected. + */ + public InetAddress getRemoteAddress() + { + return _socket_.getInetAddress(); + } + + + /** + * Verifies that the remote end of the given socket is connected to the + * the same host that the SocketClient is currently connected to. This + * is useful for doing a quick security check when a client needs to + * accept a connection from a server, such as an FTP data connection or + * a BSD R command standard error stream. + *

+ * @return True if the remote hosts are the same, false if not. + */ + public boolean verifyRemote(Socket socket) + { + InetAddress host1, host2; + + host1 = socket.getInetAddress(); + host2 = getRemoteAddress(); + + return host1.equals(host2); + } + + + /** + * Sets the SocketFactory used by the SocketClient to open socket + * connections. If the factory value is null, then a default + * factory is used (only do this to reset the factory after having + * previously altered it). + *

+ * @param factory The new SocketFactory the SocketClient should use. + */ + public void setSocketFactory(SocketFactory factory) + { + if (factory == null) + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + else + _socketFactory_ = factory; + } + + /** + * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket + * connections. If the factory value is null, then a default + * factory is used (only do this to reset the factory after having + * previously altered it). + *

+ * @param factory The new ServerSocketFactory the SocketClient should use. + * @since 2.0 + */ + public void setServerSocketFactory(ServerSocketFactory factory) { + if (factory == null) + _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; + else + _serverSocketFactory_ = factory; + } + + /** + * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's + * connect() method. + * @param connectTimeout The connection timeout to use (in ms) + * @since 2.0 + */ + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + /** + * Get the underlying socket connection timeout. + * @return + * @since 2.0 + */ + public int getConnectTimeout() { + return connectTimeout; + } + + + +} + + diff --git a/org/apache/commons/net/bsd/RCommandClient.java b/org/apache/commons/net/bsd/RCommandClient.java new file mode 100644 index 0000000..50cb87a --- /dev/null +++ b/org/apache/commons/net/bsd/RCommandClient.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.bsd; + +import java.io.IOException; +import java.io.InputStream; +import java.net.BindException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +import org.apache.commons.net.io.SocketInputStream; + +/*** + * RCommandClient is very similar to + * {@link org.apache.commons.net.bsd.RExecClient}, + * from which it is derived, and implements the rcmd() facility that + * first appeared in 4.2BSD Unix. rcmd() is the facility used by the rsh + * (rshell) and other commands to execute a command on another machine + * from a trusted host without issuing a password. The trust relationship + * between two machines is established by the contents of a machine's + * /etc/hosts.equiv file and a user's .rhosts file. These files specify + * from which hosts and accounts on those hosts rcmd() requests will be + * accepted. The only additional measure for establishing trust is that + * all client connections must originate from a port between 512 and 1023. + * Consequently, there is an upper limit to the number of rcmd connections + * that can be running simultaneously. The required ports are reserved + * ports on Unix systems, and can only be bound by a + * process running with root permissions (to accomplish this rsh, rlogin, + * and related commands usualy have the suid bit set). Therefore, on a + * Unix system, you will only be able to successfully use the RCommandClient + * class if the process runs as root. However, there is no such restriction + * on Windows95 and some other systems. The security risks are obvious. + * However, when carefully used, rcmd() can be very useful when used behind + * a firewall. + *

+ * As with virtually all of the client classes in org.apache.commons.net, this + * class derives from SocketClient. But it overrides most of its connection + * methods so that the local Socket will originate from an acceptable + * rshell port. The way to use RCommandClient is to first connect + * to the server, call the {@link #rcommand rcommand() } method, + * and then + * fetch the connection's input, output, and optionally error streams. + * Interaction with the remote command is controlled entirely through the + * I/O streams. Once you have finished processing the streams, you should + * invoke {@link org.apache.commons.net.bsd.RExecClient#disconnect disconnect() } + * to clean up properly. + *

+ * By default the standard output and standard error streams of the + * remote process are transmitted over the same connection, readable + * from the input stream returned by + * {@link org.apache.commons.net.bsd.RExecClient#getInputStream getInputStream() } + * . However, it is + * possible to tell the rshd daemon to return the standard error + * stream over a separate connection, readable from the input stream + * returned by {@link org.apache.commons.net.bsd.RExecClient#getErrorStream getErrorStream() } + * . You + * can specify that a separate connection should be created for standard + * error by setting the boolean separateErrorStream + * parameter of {@link #rcommand rcommand() } to true . + * The standard input of the remote process can be written to through + * the output stream returned by + * {@link org.apache.commons.net.bsd.RExecClient#getOutputStream getOutputStream() } + * . + *

+ *

+ * @author Daniel F. Savarese + * @see org.apache.commons.net.SocketClient + * @see RExecClient + * @see RLoginClient + ***/ + +public class RCommandClient extends RExecClient +{ + /*** + * The default rshell port. Set to 514 in BSD Unix. + ***/ + public static final int DEFAULT_PORT = 514; + + /*** + * The smallest port number an rcmd client may use. By BSD convention + * this number is 512. + ***/ + public static final int MIN_CLIENT_PORT = 512; + + /*** + * The largest port number an rcmd client may use. By BSD convention + * this number is 1023. + ***/ + public static final int MAX_CLIENT_PORT = 1023; + + // Overrides method in RExecClient in order to implement proper + // port number limitations. + @Override + InputStream _createErrorStream() throws IOException + { + int localPort; + ServerSocket server; + Socket socket; + + localPort = MAX_CLIENT_PORT; + server = null; // Keep compiler from barfing + + for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort) + { + try + { + server = _serverSocketFactory_.createServerSocket(localPort, 1, + getLocalAddress()); + } + catch (SocketException e) + { + continue; + } + break; + } + + if (localPort < MIN_CLIENT_PORT) + throw new BindException("All ports in use."); + + _output_.write(Integer.toString(server.getLocalPort()).getBytes()); + _output_.write('\0'); + _output_.flush(); + + socket = server.accept(); + server.close(); + + if (isRemoteVerificationEnabled() && !verifyRemote(socket)) + { + socket.close(); + throw new IOException( + "Security violation: unexpected connection attempt by " + + socket.getInetAddress().getHostAddress()); + } + + return (new SocketInputStream(socket, socket.getInputStream())); + } + + /*** + * The default RCommandClient constructor. Initializes the + * default port to DEFAULT_PORT . + ***/ + public RCommandClient() + { + setDefaultPort(DEFAULT_PORT); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address using a port in a range + * acceptable to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + ***/ + public void connect(InetAddress host, int port, InetAddress localAddr) + throws SocketException, BindException, IOException + { + int localPort; + + localPort = MAX_CLIENT_PORT; + + for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort) + { + try + { + _socket_ = + _socketFactory_.createSocket(host, port, localAddr, localPort); + } + catch (BindException be) { + continue; + } + catch (SocketException e) + { + continue; + } + break; + } + + if (localPort < MIN_CLIENT_PORT) + throw new BindException("All ports in use or insufficient permssion."); + + _connectAction_(); + } + + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a port in a range acceptable + * to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + ***/ + @Override + public void connect(InetAddress host, int port) + throws SocketException, IOException + { + connect(host, port, InetAddress.getLocalHost()); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a port in a range acceptable + * to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + @Override + public void connect(String hostname, int port) + throws SocketException, IOException + { + connect(InetAddress.getByName(hostname), port, InetAddress.getLocalHost()); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address using a port in a range + * acceptable to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + ***/ + public void connect(String hostname, int port, InetAddress localAddr) + throws SocketException, IOException + { + connect(InetAddress.getByName(hostname), port, localAddr); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. The + * local port must lie between MIN_CLIENT_PORT and + * MAX_CLIENT_PORT or an IllegalArgumentException will + * be thrown. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception IllegalArgumentException If an invalid local port number + * is specified. + ***/ + @Override + public void connect(InetAddress host, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException, IllegalArgumentException + { + if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT) + throw new IllegalArgumentException("Invalid port number " + localPort); + super.connect(host, port, localAddr, localPort); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. The + * local port must lie between MIN_CLIENT_PORT and + * MAX_CLIENT_PORT or an IllegalArgumentException will + * be thrown. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + * @exception IllegalArgumentException If an invalid local port number + * is specified. + ***/ + @Override + public void connect(String hostname, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException, IllegalArgumentException + { + if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT) + throw new IllegalArgumentException("Invalid port number " + localPort); + super.connect(hostname, port, localAddr, localPort); + } + + + /*** + * Remotely executes a command through the rshd daemon on the server + * to which the RCommandClient is connected. After calling this method, + * you may interact with the remote process through its standard input, + * output, and error streams. You will typically be able to detect + * the termination of the remote process after reaching end of file + * on its standard output (accessible through + * {@link #getInputStream getInputStream() }. Disconnecting + * from the server or closing the process streams before reaching + * end of file will not necessarily terminate the remote process. + *

+ * If a separate error stream is requested, the remote server will + * connect to a local socket opened by RCommandClient, providing an + * independent stream through which standard error will be transmitted. + * The local socket must originate from a secure port (512 - 1023), + * and rcommand() ensures that this will be so. + * RCommandClient will also do a simple security check when it accepts a + * connection for this error stream. If the connection does not originate + * from the remote server, an IOException will be thrown. This serves as + * a simple protection against possible hijacking of the error stream by + * an attacker monitoring the rexec() negotiation. You may disable this + * behavior with + * {@link org.apache.commons.net.bsd.RExecClient#setRemoteVerificationEnabled setRemoteVerificationEnabled()} + * . + *

+ * @param localUsername The user account on the local machine that is + * requesting the command execution. + * @param remoteUsername The account name on the server through which to + * execute the command. + * @param command The command, including any arguments, to execute. + * @param separateErrorStream True if you would like the standard error + * to be transmitted through a different stream than standard output. + * False if not. + * @exception IOException If the rcommand() attempt fails. The exception + * will contain a message indicating the nature of the failure. + ***/ + public void rcommand(String localUsername, String remoteUsername, + String command, boolean separateErrorStream) + throws IOException + { + rexec(localUsername, remoteUsername, command, separateErrorStream); + } + + + /*** + * Same as + * rcommand(localUsername, remoteUsername, command, false); + ***/ + public void rcommand(String localUsername, String remoteUsername, + String command) + throws IOException + { + rcommand(localUsername, remoteUsername, command, false); + } + +} + diff --git a/org/apache/commons/net/bsd/RExecClient.java b/org/apache/commons/net/bsd/RExecClient.java new file mode 100644 index 0000000..2924120 --- /dev/null +++ b/org/apache/commons/net/bsd/RExecClient.java @@ -0,0 +1,292 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.bsd; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; + +import org.apache.commons.net.SocketClient; +import org.apache.commons.net.io.SocketInputStream; + +/*** + * RExecClient implements the rexec() facility that first appeared in + * 4.2BSD Unix. This class will probably only be of use for connecting + * to Unix systems and only when the rexecd daemon is configured to run, + * which is a rarity these days because of the security risks involved. + * However, rexec() can be very useful for performing administrative tasks + * on a network behind a firewall. + *

+ * As with virtually all of the client classes in org.apache.commons.net, this + * class derives from SocketClient, inheriting its connection methods. + * The way to use RExecClient is to first connect + * to the server, call the {@link #rexec rexec() } method, and then + * fetch the connection's input, output, and optionally error streams. + * Interaction with the remote command is controlled entirely through the + * I/O streams. Once you have finished processing the streams, you should + * invoke {@link #disconnect disconnect() } to clean up properly. + *

+ * By default the standard output and standard error streams of the + * remote process are transmitted over the same connection, readable + * from the input stream returned by + * {@link #getInputStream getInputStream() }. However, it is + * possible to tell the rexecd daemon to return the standard error + * stream over a separate connection, readable from the input stream + * returned by {@link #getErrorStream getErrorStream() }. You + * can specify that a separate connection should be created for standard + * error by setting the boolean separateErrorStream + * parameter of {@link #rexec rexec() } to true . + * The standard input of the remote process can be written to through + * the output stream returned by + * {@link #getOutputStream getOutputSream() }. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketClient + * @see RCommandClient + * @see RLoginClient + ***/ + +public class RExecClient extends SocketClient +{ + /*** + * The default rexec port. Set to 512 in BSD Unix. + ***/ + public static final int DEFAULT_PORT = 512; + + private boolean __remoteVerificationEnabled; + + /*** + * If a separate error stream is requested, _errorStream_ + * will point to an InputStream from which the standard error of the + * remote process can be read (after a call to rexec()). Otherwise, + * _errorStream_ will be null. + ***/ + protected InputStream _errorStream_; + + // This can be overridden in local package to implement port range + // limitations of rcmd and rlogin + InputStream _createErrorStream() throws IOException + { + ServerSocket server; + Socket socket; + + server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); + + _output_.write(Integer.toString(server.getLocalPort()).getBytes()); + _output_.write('\0'); + _output_.flush(); + + socket = server.accept(); + server.close(); + + if (__remoteVerificationEnabled && !verifyRemote(socket)) + { + socket.close(); + throw new IOException( + "Security violation: unexpected connection attempt by " + + socket.getInetAddress().getHostAddress()); + } + + return (new SocketInputStream(socket, socket.getInputStream())); + } + + + /*** + * The default RExecClient constructor. Initializes the + * default port to DEFAULT_PORT . + ***/ + public RExecClient() + { + _errorStream_ = null; + setDefaultPort(DEFAULT_PORT); + } + + + /*** + * Returns the InputStream from which the standard outputof the remote + * process can be read. The input stream will only be set after a + * successful rexec() invocation. + *

+ * @return The InputStream from which the standard output of the remote + * process can be read. + ***/ + public InputStream getInputStream() + { + return _input_; + } + + + /*** + * Returns the OutputStream through which the standard input of the remote + * process can be written. The output stream will only be set after a + * successful rexec() invocation. + *

+ * @return The OutputStream through which the standard input of the remote + * process can be written. + ***/ + public OutputStream getOutputStream() + { + return _output_; + } + + + /*** + * Returns the InputStream from which the standard error of the remote + * process can be read if a separate error stream is requested from + * the server. Otherwise, null will be returned. The error stream + * will only be set after a successful rexec() invocation. + *

+ * @return The InputStream from which the standard error of the remote + * process can be read if a separate error stream is requested from + * the server. Otherwise, null will be returned. + ***/ + public InputStream getErrorStream() + { + return _errorStream_; + } + + + /*** + * Remotely executes a command through the rexecd daemon on the server + * to which the RExecClient is connected. After calling this method, + * you may interact with the remote process through its standard input, + * output, and error streams. You will typically be able to detect + * the termination of the remote process after reaching end of file + * on its standard output (accessible through + * {@link #getInputStream getInputStream() }. Disconnecting + * from the server or closing the process streams before reaching + * end of file will not necessarily terminate the remote process. + *

+ * If a separate error stream is requested, the remote server will + * connect to a local socket opened by RExecClient, providing an + * independent stream through which standard error will be transmitted. + * RExecClient will do a simple security check when it accepts a + * connection for this error stream. If the connection does not originate + * from the remote server, an IOException will be thrown. This serves as + * a simple protection against possible hijacking of the error stream by + * an attacker monitoring the rexec() negotiation. You may disable this + * behavior with {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()} + * . + *

+ * @param username The account name on the server through which to execute + * the command. + * @param password The plain text password of the user account. + * @param command The command, including any arguments, to execute. + * @param separateErrorStream True if you would like the standard error + * to be transmitted through a different stream than standard output. + * False if not. + * @exception IOException If the rexec() attempt fails. The exception + * will contain a message indicating the nature of the failure. + ***/ + public void rexec(String username, String password, + String command, boolean separateErrorStream) + throws IOException + { + int ch; + + if (separateErrorStream) + { + _errorStream_ = _createErrorStream(); + } + else + { + _output_.write('\0'); + } + + _output_.write(username.getBytes()); + _output_.write('\0'); + _output_.write(password.getBytes()); + _output_.write('\0'); + _output_.write(command.getBytes()); + _output_.write('\0'); + _output_.flush(); + + ch = _input_.read(); + if (ch > 0) + { + StringBuffer buffer = new StringBuffer(); + + while ((ch = _input_.read()) != -1 && ch != '\n') + buffer.append((char)ch); + + throw new IOException(buffer.toString()); + } + else if (ch < 0) + { + throw new IOException("Server closed connection."); + } + } + + + /*** + * Same as rexec(username, password, command, false); + ***/ + public void rexec(String username, String password, + String command) + throws IOException + { + rexec(username, password, command, false); + } + + /*** + * Disconnects from the server, closing all associated open sockets and + * streams. + *

+ * @exception IOException If there an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + if (_errorStream_ != null) + _errorStream_.close(); + _errorStream_ = null; + super.disconnect(); + } + + + /*** + * Enable or disable verification that the remote host connecting to + * create a separate error stream is the same as the host to which + * the standard out stream is connected. The default is for verification + * to be enabled. You may set this value at any time, whether the + * client is currently connected or not. + *

+ * @param enable True to enable verification, false to disable verification. + ***/ + public final void setRemoteVerificationEnabled(boolean enable) + { + __remoteVerificationEnabled = enable; + } + + /*** + * Return whether or not verification of the remote host providing a + * separate error stream is enabled. The default behavior is for + * verification to be enabled. + *

+ * @return True if verification is enabled, false if not. + ***/ + public final boolean isRemoteVerificationEnabled() + { + return __remoteVerificationEnabled; + } + +} + diff --git a/org/apache/commons/net/bsd/RLoginClient.java b/org/apache/commons/net/bsd/RLoginClient.java new file mode 100644 index 0000000..3d7c63c --- /dev/null +++ b/org/apache/commons/net/bsd/RLoginClient.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.bsd; + +import java.io.IOException; + +/*** + * RLoginClient is very similar to + * {@link org.apache.commons.net.bsd.RCommandClient}, + * from which it is derived, and uses the rcmd() facility implemented + * in RCommandClient to implement the functionality of the rlogin command that + * first appeared in 4.2BSD Unix. rlogin is a command used to login to + * a remote machine from a trusted host, sometimes without issuing a + * password. The trust relationship is the same as described in + * the documentation for + * {@link org.apache.commons.net.bsd.RCommandClient}. + *

+ * As with virtually all of the client classes in org.apache.commons.net, this + * class derives from SocketClient. But it relies on the connection + * methods defined in RcommandClient which ensure that the local Socket + * will originate from an acceptable rshell port. The way to use + * RLoginClient is to first connect + * to the server, call the {@link #rlogin rlogin() } method, + * and then + * fetch the connection's input and output streams. + * Interaction with the remote command is controlled entirely through the + * I/O streams. Once you have finished processing the streams, you should + * invoke {@link org.apache.commons.net.bsd.RExecClient#disconnect disconnect() } + * to clean up properly. + *

+ * The standard output and standard error streams of the + * remote process are transmitted over the same connection, readable + * from the input stream returned by + * {@link org.apache.commons.net.bsd.RExecClient#getInputStream getInputStream() } + * . Unlike RExecClient and RCommandClient, it is + * not possible to tell the rlogind daemon to return the standard error + * stream over a separate connection. + * {@link org.apache.commons.net.bsd.RExecClient#getErrorStream getErrorStream() } + * will always return null. + * The standard input of the remote process can be written to through + * the output stream returned by + * {@link org.apache.commons.net.bsd.RExecClient#getOutputStream getOutputSream() } + * . + *

+ *

+ * @author Daniel F. Savarese + * @see org.apache.commons.net.SocketClient + * @see RExecClient + * @see RCommandClient + ***/ + +public class RLoginClient extends RCommandClient +{ + /*** + * The default rlogin port. Set to 513 in BSD Unix and according + * to RFC 1282. + ***/ + public static final int DEFAULT_PORT = 513; + + /*** + * The default RLoginClient constructor. Initializes the + * default port to DEFAULT_PORT . + ***/ + public RLoginClient() + { + setDefaultPort(DEFAULT_PORT); + } + + + /*** + * Logins into a remote machine through the rlogind daemon on the server + * to which the RLoginClient is connected. After calling this method, + * you may interact with the remote login shell through its standard input + * and output streams. Standard error is sent over the same stream as + * standard output. You will typically be able to detect + * the termination of the remote login shell after reaching end of file + * on its standard output (accessible through + * {@link #getInputStream getInputStream() }. Disconnecting + * from the server or closing the process streams before reaching + * end of file will terminate the remote login shell in most cases. + *

+ * If user authentication fails, the rlogind daemon will request that + * a password be entered interactively. You will be able to read the + * prompt from the output stream of the RLoginClient and write the + * password to the input stream of the RLoginClient. + *

+ * @param localUsername The user account on the local machine that is + * trying to login to the remote host. + * @param remoteUsername The account name on the server that is + * being logged in to. + * @param terminalType The name of the user's terminal (e.g., "vt100", + * "network", etc.) + * @param terminalSpeed The speed of the user's terminal, expressed + * as a baud rate or bps (e.g., 9600 or 38400) + * @exception IOException If the rlogin() attempt fails. The exception + * will contain a message indicating the nature of the failure. + ***/ + public void rlogin(String localUsername, String remoteUsername, + String terminalType, int terminalSpeed) + throws IOException + { + rexec(localUsername, remoteUsername, terminalType + "/" + terminalSpeed, + false); + } + + /*** + * Same as the other rlogin method, but no terminal speed is defined. + ***/ + public void rlogin(String localUsername, String remoteUsername, + String terminalType) + throws IOException + { + rexec(localUsername, remoteUsername, terminalType, false); + } + +} diff --git a/org/apache/commons/net/chargen/CharGenTCPClient.java b/org/apache/commons/net/chargen/CharGenTCPClient.java new file mode 100644 index 0000000..a023e58 --- /dev/null +++ b/org/apache/commons/net/chargen/CharGenTCPClient.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.chargen; + +import java.io.InputStream; + +import org.apache.commons.net.SocketClient; + +/*** + * The CharGenTCPClient class is a TCP implementation of a client for the + * character generator protocol described in RFC 864. It can also be + * used for Systat (RFC 866), Quote of the Day (RFC 865), and netstat + * (port 15). All of these protocols involve connecting to the appropriate + * port, and reading data from an input stream. The chargen protocol + * actually sends data until the receiving end closes the connection. All + * of the others send only a fixed amount of data and then close the + * connection. + *

+ * To use the CharGenTCPClient class, just establish a + * connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * and call {@link #getInputStream getInputStream() } to access + * the data. Don't close the input stream when you're done with it. Rather, + * call {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to clean up properly. + *

+ *

+ * @author Daniel F. Savarese + * @see CharGenUDPClient + ***/ + +public final class CharGenTCPClient extends SocketClient +{ + /*** The systat port value of 11 according to RFC 866. ***/ + public static final int SYSTAT_PORT = 11; + /*** The netstat port value of 19. ***/ + public static final int NETSTAT_PORT = 15; + /*** The quote of the day port value of 17 according to RFC 865. ***/ + public static final int QUOTE_OF_DAY_PORT = 17; + /*** The character generator port value of 19 according to RFC 864. ***/ + public static final int CHARGEN_PORT = 19; + /*** The default chargen port. It is set to 19 according to RFC 864. ***/ + public static final int DEFAULT_PORT = 19; + + /*** + * The default constructor for CharGenTCPClient. It merely sets the + * default port to DEFAULT_PORT . + ***/ + public CharGenTCPClient () + { + setDefaultPort(DEFAULT_PORT); + } + + /*** + * Returns an InputStream from which the server generated data can be + * read. You should NOT close the InputStream when you're finished + * reading from it. Rather, you should call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to clean up properly. + *

+ * @return An InputStream from which the server generated data can be read. + ***/ + public InputStream getInputStream() + { + return _input_; + } +} + + + + diff --git a/org/apache/commons/net/chargen/CharGenUDPClient.java b/org/apache/commons/net/chargen/CharGenUDPClient.java new file mode 100644 index 0000000..f9a349a --- /dev/null +++ b/org/apache/commons/net/chargen/CharGenUDPClient.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.chargen; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; + +import org.apache.commons.net.DatagramSocketClient; + +/*** + * The CharGenUDPClient class is a UDP implementation of a client for the + * character generator protocol described in RFC 864. It can also be + * used for Systat (RFC 866), Quote of the Day (RFC 865), and netstat + * (port 15). All of these protocols involve sending a datagram to the + * appropriate port, and reading data contained in one or more reply + * datagrams. The chargen and quote of the day protocols only send + * one reply datagram containing 512 bytes or less of data. The other + * protocols may reply with more than one datagram, in which case you + * must wait for a timeout to determine that all reply datagrams have + * been sent. + *

+ * To use the CharGenUDPClient class, just open a local UDP port + * with {@link org.apache.commons.net.DatagramSocketClient#open open } + * and call {@link #send send } to send the datagram that will + * initiate the data reply. For chargen or quote of the day, just + * call {@link #receive receive }, and you're done. For netstat and + * systat, call receive in a while loop, and catch a SocketException and + * InterruptedIOException to detect a timeout (don't forget to set the + * timeout duration beforehand). Don't forget to call + * {@link org.apache.commons.net.DatagramSocketClient#close close() } + * to clean up properly. + *

+ *

+ * @author Daniel F. Savarese + * @see CharGenTCPClient + ***/ + +public final class CharGenUDPClient extends DatagramSocketClient +{ + /*** The systat port value of 11 according to RFC 866. ***/ + public static final int SYSTAT_PORT = 11; + /*** The netstat port value of 19. ***/ + public static final int NETSTAT_PORT = 15; + /*** The quote of the day port value of 17 according to RFC 865. ***/ + public static final int QUOTE_OF_DAY_PORT = 17; + /*** The character generator port value of 19 according to RFC 864. ***/ + public static final int CHARGEN_PORT = 19; + /*** The default chargen port. It is set to 19 according to RFC 864. ***/ + public static final int DEFAULT_PORT = 19; + + private byte[] __receiveData; + private DatagramPacket __receivePacket; + private DatagramPacket __sendPacket; + + /*** + * The default CharGenUDPClient constructor. It initializes some internal + * data structures for sending and receiving the necessary datagrams for + * the chargen and related protocols. + ***/ + public CharGenUDPClient() + { + // CharGen return packets have a maximum length of 512 + __receiveData = new byte[512]; + __receivePacket = new DatagramPacket(__receiveData, 512); + __sendPacket = new DatagramPacket(new byte[0], 0); + } + + + /*** + * Sends the data initiation datagram. This data in the packet is ignored + * by the server, and merely serves to signal that the server should send + * its reply. + *

+ * @param host The address of the server. + * @param port The port of the service. + * @exception IOException If an error occurs while sending the datagram. + ***/ + public void send(InetAddress host, int port) throws IOException + { + __sendPacket.setAddress(host); + __sendPacket.setPort(port); + _socket_.send(__sendPacket); + } + + /*** Same as send(host, CharGenUDPClient.DEFAULT_PORT); ***/ + public void send(InetAddress host) throws IOException + { + send(host, DEFAULT_PORT); + } + + /*** + * Receive the reply data from the server. This will always be 512 bytes + * or less. Chargen and quote of the day only return one packet. Netstat + * and systat require multiple calls to receive() with timeout detection. + *

+ * @return The reply data from the server. + * @exception IOException If an error occurs while receiving the datagram. + ***/ + public byte[] receive() throws IOException + { + int length; + byte[] result; + + _socket_.receive(__receivePacket); + + result = new byte[length = __receivePacket.getLength()]; + System.arraycopy(__receiveData, 0, result, 0, length); + + return result; + } + +} + diff --git a/org/apache/commons/net/daytime/DaytimeTCPClient.java b/org/apache/commons/net/daytime/DaytimeTCPClient.java new file mode 100644 index 0000000..a77c8c1 --- /dev/null +++ b/org/apache/commons/net/daytime/DaytimeTCPClient.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.daytime; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.commons.net.SocketClient; + +/*** + * The DaytimeTCPClient class is a TCP implementation of a client for the + * Daytime protocol described in RFC 867. To use the class, merely + * establish a connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * and call {@link #getTime getTime() } to retrieve the daytime + * string, then + * call {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to close the connection properly. + *

+ *

+ * @author Daniel F. Savarese + * @see DaytimeUDPClient + ***/ + +public final class DaytimeTCPClient extends SocketClient +{ + /*** The default daytime port. It is set to 13 according to RFC 867. ***/ + public static final int DEFAULT_PORT = 13; + + // Received dates will likely be less than 64 characters. + // This is a temporary buffer used while receiving data. + private char[] __buffer = new char[64]; + + /*** + * The default DaytimeTCPClient constructor. It merely sets the default + * port to DEFAULT_PORT . + ***/ + public DaytimeTCPClient () + { + setDefaultPort(DEFAULT_PORT); + } + + /*** + * Retrieves the time string from the server and returns it. The + * server will have closed the connection at this point, so you should + * call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * after calling this method. To retrieve another time, you must + * initiate another connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before calling getTime() again. + *

+ * @return The time string retrieved from the server. + * @exception IOException If an error occurs while fetching the time string. + ***/ + public String getTime() throws IOException + { + int read; + StringBuffer result = new StringBuffer(__buffer.length); + BufferedReader reader; + + reader = new BufferedReader(new InputStreamReader(_input_)); + + while (true) + { + read = reader.read(__buffer, 0, __buffer.length); + if (read <= 0) + break; + result.append(__buffer, 0, read); + } + + return result.toString(); + } + +} + diff --git a/org/apache/commons/net/daytime/DaytimeUDPClient.java b/org/apache/commons/net/daytime/DaytimeUDPClient.java new file mode 100644 index 0000000..64eef9d --- /dev/null +++ b/org/apache/commons/net/daytime/DaytimeUDPClient.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.daytime; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; + +import org.apache.commons.net.DatagramSocketClient; + +/*** + * The DaytimeUDPClient class is a UDP implementation of a client for the + * Daytime protocol described in RFC 867. To use the class, merely + * open a local datagram socket with + * {@link org.apache.commons.net.DatagramSocketClient#open open } + * and call {@link #getTime getTime } to retrieve the daytime + * string, then + * call {@link org.apache.commons.net.DatagramSocketClient#close close } + * to close the connection properly. Unlike + * {@link org.apache.commons.net.daytime.DaytimeTCPClient}, + * successive calls to {@link #getTime getTime } are permitted + * without re-establishing a connection. That is because UDP is a + * connectionless protocol and the Daytime protocol is stateless. + *

+ *

+ * @author Daniel F. Savarese + * @see DaytimeTCPClient + ***/ + +public final class DaytimeUDPClient extends DatagramSocketClient +{ + /*** The default daytime port. It is set to 13 according to RFC 867. ***/ + public static final int DEFAULT_PORT = 13; + + private byte[] __dummyData = new byte[1]; + // Received dates should be less than 256 bytes + private byte[] __timeData = new byte[256]; + + /*** + * Retrieves the time string from the specified server and port and + * returns it. + *

+ * @param host The address of the server. + * @param port The port of the service. + * @return The time string. + * @exception IOException If an error occurs while retrieving the time. + ***/ + public String getTime(InetAddress host, int port) throws IOException + { + DatagramPacket sendPacket, receivePacket; + + sendPacket = + new DatagramPacket(__dummyData, __dummyData.length, host, port); + receivePacket = new DatagramPacket(__timeData, __timeData.length); + + _socket_.send(sendPacket); + _socket_.receive(receivePacket); + + return new String(receivePacket.getData(), 0, receivePacket.getLength()); + } + + /*** Same as getTime(host, DaytimeUDPClient.DEFAULT_PORT); ***/ + public String getTime(InetAddress host) throws IOException + { + return getTime(host, DEFAULT_PORT); + } + +} + diff --git a/org/apache/commons/net/discard/DiscardTCPClient.java b/org/apache/commons/net/discard/DiscardTCPClient.java new file mode 100644 index 0000000..7a771c9 --- /dev/null +++ b/org/apache/commons/net/discard/DiscardTCPClient.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.discard; + +import java.io.OutputStream; + +import org.apache.commons.net.SocketClient; + +/*** + * The DiscardTCPClient class is a TCP implementation of a client for the + * Discard protocol described in RFC 863. To use the class, merely + * establish a connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * and call {@link #getOutputStream getOutputStream() } to + * retrieve the discard output stream. Don't close the output stream + * when you're done writing to it. Rather, call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to clean up properly. + *

+ *

+ * @author Daniel F. Savarese + * @see DiscardUDPClient + ***/ + +public class DiscardTCPClient extends SocketClient +{ + /*** The default discard port. It is set to 9 according to RFC 863. ***/ + public static final int DEFAULT_PORT = 9; + + /*** + * The default DiscardTCPClient constructor. It merely sets the default + * port to DEFAULT_PORT . + ***/ + public DiscardTCPClient () + { + setDefaultPort(DEFAULT_PORT); + } + + /*** + * Returns an OutputStream through which you may write data to the server. + * You should NOT close the OutputStream when you're finished + * reading from it. Rather, you should call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to clean up properly. + *

+ * @return An OutputStream through which you can write data to the server. + ***/ + public OutputStream getOutputStream() + { + return _output_; + } +} diff --git a/org/apache/commons/net/discard/DiscardUDPClient.java b/org/apache/commons/net/discard/DiscardUDPClient.java new file mode 100644 index 0000000..a81b955 --- /dev/null +++ b/org/apache/commons/net/discard/DiscardUDPClient.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.discard; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; + +import org.apache.commons.net.DatagramSocketClient; + +/*** + * The DiscardUDPClient class is a UDP implementation of a client for the + * Discard protocol described in RFC 863. To use the class, + * just open a local UDP port + * with {@link org.apache.commons.net.DatagramSocketClient#open open } + * and call {@link #send send } to send datagrams to the server + * After you're done sending discard data, call + * {@link org.apache.commons.net.DatagramSocketClient#close close() } + * to clean up properly. + *

+ *

+ * @author Daniel F. Savarese + * @see DiscardTCPClient + ***/ + +public class DiscardUDPClient extends DatagramSocketClient +{ + /*** The default discard port. It is set to 9 according to RFC 863. ***/ + public static final int DEFAULT_PORT = 9; + + DatagramPacket _sendPacket; + + public DiscardUDPClient() + { + _sendPacket = new DatagramPacket(new byte[0], 0); + } + + + /*** + * Sends the specified data to the specified server at the specified port. + *

+ * @param data The discard data to send. + * @param length The length of the data to send. Should be less than + * or equal to the length of the data byte array. + * @param host The address of the server. + * @param port The service port. + * @exception IOException If an error occurs during the datagram send + * operation. + ***/ + public void send(byte[] data, int length, InetAddress host, int port) + throws IOException + { + _sendPacket.setData(data); + _sendPacket.setLength(length); + _sendPacket.setAddress(host); + _sendPacket.setPort(port); + _socket_.send(_sendPacket); + } + + + /*** + * Same as + * send(data, length, host. DiscardUDPClient.DEFAULT_PORT). + ***/ + public void send(byte[] data, int length, InetAddress host) + throws IOException + { + send(data, length, host, DEFAULT_PORT); + } + + + /*** + * Same as + * send(data, data.length, host. DiscardUDPClient.DEFAULT_PORT). + ***/ + public void send(byte[] data, InetAddress host) throws IOException + { + send(data, data.length, host, DEFAULT_PORT); + } + +} + diff --git a/org/apache/commons/net/echo/EchoTCPClient.java b/org/apache/commons/net/echo/EchoTCPClient.java new file mode 100644 index 0000000..b4d43e2 --- /dev/null +++ b/org/apache/commons/net/echo/EchoTCPClient.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.echo; + +import java.io.InputStream; + +import org.apache.commons.net.discard.DiscardTCPClient; + +/*** + * The EchoTCPClient class is a TCP implementation of a client for the + * Echo protocol described in RFC 862. To use the class, merely + * establish a connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * and call {@link DiscardTCPClient#getOutputStream getOutputStream() } to + * retrieve the echo output stream and + * {@link #getInputStream getInputStream() } + * to get the echo input stream. + * Don't close either stream when you're done using them. Rather, call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to clean up properly. + *

+ *

+ * @author Daniel F. Savarese + * @see EchoUDPClient + * @see DiscardTCPClient + ***/ + +public final class EchoTCPClient extends DiscardTCPClient +{ + /*** The default echo port. It is set to 7 according to RFC 862. ***/ + public static final int DEFAULT_PORT = 7; + + /*** + * The default EchoTCPClient constructor. It merely sets the default + * port to DEFAULT_PORT . + ***/ + public EchoTCPClient () + { + setDefaultPort(DEFAULT_PORT); + } + + /*** + * Returns an InputStream from which you may read echoed data from + * the server. You should NOT close the InputStream when you're finished + * reading from it. Rather, you should call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to clean up properly. + *

+ * @return An InputStream from which you can read echoed data from the + * server. + ***/ + public InputStream getInputStream() + { + return _input_; + } + +} diff --git a/org/apache/commons/net/echo/EchoUDPClient.java b/org/apache/commons/net/echo/EchoUDPClient.java new file mode 100644 index 0000000..70a4898 --- /dev/null +++ b/org/apache/commons/net/echo/EchoUDPClient.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.echo; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; + +import org.apache.commons.net.discard.DiscardUDPClient; + +/*** + * The EchoUDPClient class is a UDP implementation of a client for the + * Echo protocol described in RFC 862. To use the class, + * just open a local UDP port + * with {@link org.apache.commons.net.DatagramSocketClient#open open } + * and call {@link #send send } to send datagrams to the server, + * then call {@link #receive receive } to receive echoes. + * After you're done echoing data, call + * {@link org.apache.commons.net.DatagramSocketClient#close close() } + * to clean up properly. + *

+ *

+ * @author Daniel F. Savarese + * @see EchoTCPClient + * @see DiscardUDPClient + ***/ + +public final class EchoUDPClient extends DiscardUDPClient +{ + /*** The default echo port. It is set to 7 according to RFC 862. ***/ + public static final int DEFAULT_PORT = 7; + + private DatagramPacket __receivePacket = new DatagramPacket(new byte[0], 0); + + /*** + * Sends the specified data to the specified server at the default echo + * port. + *

+ * @param data The echo data to send. + * @param length The length of the data to send. Should be less than + * or equal to the length of the data byte array. + * @param host The address of the server. + * @exception IOException If an error occurs during the datagram send + * operation. + ***/ + @Override + public void send(byte[] data, int length, InetAddress host) + throws IOException + { + send(data, length, host, DEFAULT_PORT); + } + + + /*** Same as send(data, data.length, host) ***/ + @Override + public void send(byte[] data, InetAddress host) throws IOException + { + send(data, data.length, host, DEFAULT_PORT); + } + + + /*** + * Receives echoed data and returns its length. The data may be divided + * up among multiple datagrams, requiring multiple calls to receive. + * Also, the UDP packets will not necessarily arrive in the same order + * they were sent. + *

+ * @return Length of actual data received. + * @exception IOException If an error occurs while receiving the data. + ***/ + public int receive(byte[] data, int length) throws IOException + { + __receivePacket.setData(data); + __receivePacket.setLength(length); + _socket_.receive(__receivePacket); + return __receivePacket.getLength(); + } + + /*** Same as receive(data, data.length) ***/ + public int receive(byte[] data) throws IOException + { + return receive(data, data.length); + } + +} + diff --git a/org/apache/commons/net/finger/FingerClient.java b/org/apache/commons/net/finger/FingerClient.java new file mode 100644 index 0000000..d3b6893 --- /dev/null +++ b/org/apache/commons/net/finger/FingerClient.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.net.finger; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; + +import org.apache.commons.net.SocketClient; + +/*** + * The FingerClient class implements the client side of the Internet Finger + * Protocol defined in RFC 1288. To finger a host you create a + * FingerClient instance, connect to the host, query the host, and finally + * disconnect from the host. If the finger service you want to query is on + * a non-standard port, connect to the host at that port. + * Here's a sample use: + *

+ *    FingerClient finger;
+ *
+ *    finger = new FingerClient();
+ *
+ *    try {
+ *      finger.connect("foo.bar.com");
+ *      System.out.println(finger.query("foobar", false));
+ *      finger.disconnect();
+ *    } catch(IOException e) {
+ *      System.err.println("Error I/O exception: " + e.getMessage());
+ *      return;
+ *    }
+ * 
+ *

+ *

+ * @author Daniel F. Savarese + ***/ + +public class FingerClient extends SocketClient +{ + /*** + * The default FINGER port. Set to 79 according to RFC 1288. + ***/ + public static final int DEFAULT_PORT = 79; + + private static final String __LONG_FLAG = "/W "; + + private transient StringBuffer __query = new StringBuffer(64); + private transient char[] __buffer = new char[1024]; + + /*** + * The default FingerClient constructor. Initializes the + * default port to DEFAULT_PORT . + ***/ + public FingerClient() + { + setDefaultPort(DEFAULT_PORT); + } + + + /*** + * Fingers a user at the connected host and returns the output + * as a String. You must first connect to a finger server before + * calling this method, and you should disconnect afterward. + *

+ * @param longOutput Set to true if long output is requested, false if not. + * @param username The name of the user to finger. + * @return The result of the finger query. + * @exception IOException If an I/O error occurs while reading the socket. + ***/ + public String query(boolean longOutput, String username) throws IOException + { + int read; + StringBuffer result = new StringBuffer(__buffer.length); + BufferedReader input; + + input = + new BufferedReader(new InputStreamReader(getInputStream(longOutput, + username))); + + while (true) + { + read = input.read(__buffer, 0, __buffer.length); + if (read <= 0) + break; + result.append(__buffer, 0, read); + } + + input.close(); + + return result.toString(); + } + + + /*** + * Fingers the connected host and returns the output + * as a String. You must first connect to a finger server before + * calling this method, and you should disconnect afterward. + * This is equivalent to calling query(longOutput, "") . + *

+ * @param longOutput Set to true if long output is requested, false if not. + * @return The result of the finger query. + * @exception IOException If an I/O error occurs while reading the socket. + ***/ + public String query(boolean longOutput) throws IOException + { + return query(longOutput, ""); + } + + + /*** + * Fingers a user and returns the input stream from the network connection + * of the finger query. You must first connect to a finger server before + * calling this method, and you should disconnect after finishing reading + * the stream. + *

+ * @param longOutput Set to true if long output is requested, false if not. + * @param username The name of the user to finger. + * @return The InputStream of the network connection of the finger query. + * Can be read to obtain finger results. + * @exception IOException If an I/O error during the operation. + ***/ + public InputStream getInputStream(boolean longOutput, String username) + throws IOException + { + return getInputStream(longOutput, username, null); + } + + /*** + * Fingers a user and returns the input stream from the network connection + * of the finger query. You must first connect to a finger server before + * calling this method, and you should disconnect after finishing reading + * the stream. + *

+ * @param longOutput Set to true if long output is requested, false if not. + * @param username The name of the user to finger. + * @param encoding the character encoding that should be used for the query, + * null for the platform's default encoding + * @return The InputStream of the network connection of the finger query. + * Can be read to obtain finger results. + * @exception IOException If an I/O error during the operation. + ***/ + public InputStream getInputStream(boolean longOutput, String username, String encoding) + throws IOException + { + DataOutputStream output; + + __query.setLength(0); + if (longOutput) + __query.append(__LONG_FLAG); + __query.append(username); + __query.append(SocketClient.NETASCII_EOL); + + byte[] encodedQuery = + (encoding == null ? __query.toString().getBytes() : __query.toString().getBytes(encoding)); + + output = new DataOutputStream(new BufferedOutputStream(_output_, 1024)); + output.write(encodedQuery, 0, encodedQuery.length); + output.flush(); + + return _input_; + } + + + /*** + * Fingers the connected host and returns the input stream from + * the network connection of the finger query. This is equivalent to + * calling getInputStream(longOutput, ""). You must first connect to a + * finger server before calling this method, and you should disconnect + * after finishing reading the stream. + *

+ * @param longOutput Set to true if long output is requested, false if not. + * @return The InputStream of the network connection of the finger query. + * Can be read to obtain finger results. + * @exception IOException If an I/O error during the operation. + ***/ + public InputStream getInputStream(boolean longOutput) throws IOException + { + return getInputStream(longOutput, ""); + } + +} diff --git a/org/apache/commons/net/ftp/Configurable.class b/org/apache/commons/net/ftp/Configurable.class new file mode 100644 index 0000000..abcae1f Binary files /dev/null and b/org/apache/commons/net/ftp/Configurable.class differ diff --git a/org/apache/commons/net/ftp/Configurable.java b/org/apache/commons/net/ftp/Configurable.java new file mode 100644 index 0000000..5e8e749 --- /dev/null +++ b/org/apache/commons/net/ftp/Configurable.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + + +/** + * This interface adds the aspect of configurability by means of + * a supplied FTPClientConfig object to other classes in the + * system, especially listing parsers. + */ +public interface Configurable { + + /** + * @param config the object containing the configuration data + * @throws IllegalArgumentException if the elements of the + * config are somehow inadequate to configure the + * Configurable object. + */ + public void configure(FTPClientConfig config); +} diff --git a/org/apache/commons/net/ftp/FTP.class b/org/apache/commons/net/ftp/FTP.class new file mode 100644 index 0000000..a363d55 Binary files /dev/null and b/org/apache/commons/net/ftp/FTP.class differ diff --git a/org/apache/commons/net/ftp/FTP.java b/org/apache/commons/net/ftp/FTP.java new file mode 100644 index 0000000..6e2eff8 --- /dev/null +++ b/org/apache/commons/net/ftp/FTP.java @@ -0,0 +1,1513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Arrays; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ProtocolCommandListener; +import org.apache.commons.net.ProtocolCommandSupport; +import org.apache.commons.net.SocketClient; + +/*** + * FTP provides the basic the functionality necessary to implement your + * own FTP client. It extends org.apache.commons.net.SocketClient since + * extending TelnetClient was causing unwanted behavior (like connections + * that did not time out properly). + *

+ * To derive the full benefits of the FTP class requires some knowledge + * of the FTP protocol defined in RFC 959. However, there is no reason + * why you should have to use the FTP class. The + * {@link org.apache.commons.net.ftp.FTPClient} class, + * derived from FTP, + * implements all the functionality required of an FTP client. The + * FTP class is made public to provide access to various FTP constants + * and to make it easier for adventurous programmers (or those with + * special needs) to interact with the FTP protocol and implement their + * own clients. A set of methods with names corresponding to the FTP + * command names are provided to facilitate this interaction. + *

+ * You should keep in mind that the FTP server may choose to prematurely + * close a connection if the client has been idle for longer than a + * given time period (usually 900 seconds). The FTP class will detect a + * premature FTP server connection closing when it receives a + * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } + * response to a command. + * When that occurs, the FTP class method encountering that reply will throw + * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * . FTPConectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * , you must disconnect the connection with + * {@link #disconnect disconnect() } to properly clean up the + * system resources used by FTP. Before disconnecting, you may check the + * last reply code and text with + * {@link #getReplyCode getReplyCode }, + * {@link #getReplyString getReplyString }, + * and {@link #getReplyStrings getReplyStrings}. + * You may avoid server disconnections while the client is idle by + * periodicaly sending NOOP commands to the server. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @author Joseph Hindsley + * @see FTPClient + * @see FTPConnectionClosedException + * @see org.apache.commons.net.MalformedServerReplyException + * @version $Id: FTP.java 658520 2008-05-21 01:14:11Z sebb $ + ***/ + +public class FTP extends SocketClient +{ + /*** The default FTP data port (20). ***/ + public static final int DEFAULT_DATA_PORT = 20; + /*** The default FTP control port (21). ***/ + public static final int DEFAULT_PORT = 21; + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as ASCII. This is the default file type. All constants + * ending in FILE_TYPE are used to indicate file types. + ***/ + public static final int ASCII_FILE_TYPE = 0; + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as EBCDIC. Note however that there are several different + * EBCDIC formats. All constants ending in FILE_TYPE + * are used to indicate file types. + ***/ + public static final int EBCDIC_FILE_TYPE = 1; + + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as a binary image, i.e., no translations should be + * performed. All constants ending in FILE_TYPE are used to + * indicate file types. + ***/ + public static final int BINARY_FILE_TYPE = 2; + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as a local type. All constants ending in + * FILE_TYPE are used to indicate file types. + ***/ + public static final int LOCAL_FILE_TYPE = 3; + + /*** + * A constant used for text files to indicate a non-print text format. + * This is the default format. + * All constants ending in TEXT_FORMAT are used to indicate + * text formatting for text transfers (both ASCII and EBCDIC). + ***/ + public static final int NON_PRINT_TEXT_FORMAT = 4; + + /*** + * A constant used to indicate a text file contains format vertical format + * control characters. + * All constants ending in TEXT_FORMAT are used to indicate + * text formatting for text transfers (both ASCII and EBCDIC). + ***/ + public static final int TELNET_TEXT_FORMAT = 5; + + /*** + * A constant used to indicate a text file contains ASA vertical format + * control characters. + * All constants ending in TEXT_FORMAT are used to indicate + * text formatting for text transfers (both ASCII and EBCDIC). + ***/ + public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6; + + /*** + * A constant used to indicate a file is to be treated as a continuous + * sequence of bytes. This is the default structure. All constants ending + * in _STRUCTURE are used to indicate file structure for + * file transfers. + ***/ + public static final int FILE_STRUCTURE = 7; + + /*** + * A constant used to indicate a file is to be treated as a sequence + * of records. All constants ending in _STRUCTURE + * are used to indicate file structure for file transfers. + ***/ + public static final int RECORD_STRUCTURE = 8; + + /*** + * A constant used to indicate a file is to be treated as a set of + * independent indexed pages. All constants ending in + * _STRUCTURE are used to indicate file structure for file + * transfers. + ***/ + public static final int PAGE_STRUCTURE = 9; + + /*** + * A constant used to indicate a file is to be transfered as a stream + * of bytes. This is the default transfer mode. All constants ending + * in TRANSFER_MODE are used to indicate file transfer + * modes. + ***/ + public static final int STREAM_TRANSFER_MODE = 10; + + /*** + * A constant used to indicate a file is to be transfered as a series + * of blocks. All constants ending in TRANSFER_MODE are used + * to indicate file transfer modes. + ***/ + public static final int BLOCK_TRANSFER_MODE = 11; + + /*** + * A constant used to indicate a file is to be transfered as FTP + * compressed data. All constants ending in TRANSFER_MODE + * are used to indicate file transfer modes. + ***/ + public static final int COMPRESSED_TRANSFER_MODE = 12; + + // We have to ensure that the protocol communication is in ASCII + // but we use ISO-8859-1 just in case 8-bit characters cross + // the wire. + /** + * The default character encoding used for communicating over an + * FTP control connection. The default encoding is an + * ASCII-compatible encoding. Some FTP servers expect other + * encodings. You can change the encoding used by an FTP instance + * with {@link #setControlEncoding setControlEncoding}. + */ + public static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1"; + private static final String __modes = "AEILNTCFRPSBC"; + + private StringBuilder __commandBuffer = new StringBuilder(); + + protected int _replyCode; + protected ArrayList _replyLines; + protected boolean _newReplyString; + protected String _replyString; + protected String _controlEncoding; + + /** + * This is used to signal whether a block of multiline responses beginning + * with xxx must be terminated by the same numeric code xxx + * See section 4.2 of RFX 959 for details. + */ + protected boolean strictMultilineParsing = false; + + /** + * Wraps SocketClient._input_ to facilitate the writing of text + * to the FTP control connection. Do not access the control + * connection via SocketClient._input_. This member starts + * with a null value, is initialized in {@link #_connectAction_}, + * and set to null in {@link #disconnect}. + */ + protected BufferedReader _controlInput_; + + /** + * Wraps SocketClient._output_ to facilitate the reading of text + * from the FTP control connection. Do not access the control + * connection via SocketClient._output_. This member starts + * with a null value, is initialized in {@link #_connectAction_}, + * and set to null in {@link #disconnect}. + */ + protected BufferedWriter _controlOutput_; + + /*** + * A ProtocolCommandSupport object used to manage the registering of + * ProtocolCommandListeners and te firing of ProtocolCommandEvents. + ***/ + protected ProtocolCommandSupport _commandSupport_; + + /*** + * The default FTP constructor. Sets the default port to + * DEFAULT_PORT and initializes internal data structures + * for saving FTP reply information. + ***/ + public FTP() + { + super(); + setDefaultPort(DEFAULT_PORT); + _replyLines = new ArrayList(); + _newReplyString = false; + _replyString = null; + _commandSupport_ = new ProtocolCommandSupport(this); + _controlEncoding = DEFAULT_CONTROL_ENCODING; + } + + // The RFC-compliant multiline termination check + private boolean __strictCheck(String line, String code) { + return (!(line.startsWith(code) && line.charAt(3) == ' ')); + } + + // The strict check is too strong a condition because of non-conforming ftp + // servers like ftp.funet.fi which sent 226 as the last line of a + // 426 multi-line reply in response to ls /. We relax the condition to + // test that the line starts with a digit rather than starting with + // the code. + private boolean __lenientCheck(String line) { + return (!(line.length() >= 4 && line.charAt(3) != '-' && + Character.isDigit(line.charAt(0)))); + } + + private void __getReply() throws IOException + { + int length; + + _newReplyString = true; + _replyLines.clear(); + + String line = _controlInput_.readLine(); + + if (line == null) + throw new FTPConnectionClosedException( + "Connection closed without indication."); + + // In case we run into an anomaly we don't want fatal index exceptions + // to be thrown. + length = line.length(); + if (length < 3) + throw new MalformedServerReplyException( + "Truncated server reply: " + line); + + String code = null; + try + { + code = line.substring(0, 3); + _replyCode = Integer.parseInt(code); + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse response code.\nServer Reply: " + line); + } + + _replyLines.add(line); + + // Get extra lines if message continues. + if (length > 3 && line.charAt(3) == '-') + { + do + { + line = _controlInput_.readLine(); + + if (line == null) + throw new FTPConnectionClosedException( + "Connection closed without indication."); + + _replyLines.add(line); + + // The length() check handles problems that could arise from readLine() + // returning too soon after encountering a naked CR or some other + // anomaly. + } + while ( isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line)); + } + + if (_commandSupport_.getListenerCount() > 0) { + _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); + } + + if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { + throw new FTPConnectionClosedException("FTP response 421 received. Server closed connection."); + } + } + + /** + * Initiates control connections and gets initial reply. + * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. + */ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + _controlInput_ = + new BufferedReader(new InputStreamReader(_socket_.getInputStream(), + getControlEncoding())); + _controlOutput_ = + new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), + getControlEncoding())); + __getReply(); + // If we received code 120, we have to fetch completion reply. + if (FTPReply.isPositivePreliminary(_replyCode)) + __getReply(); + } + + + /** + * Sets the character encoding used by the FTP control connection. + * Some FTP servers require that commands be issued in a non-ASCII + * encoding like UTF-8 so that filenames with multi-byte character + * representations (e.g, Big 8) can be specified. + * + * @param encoding The new character encoding for the control connection. + */ + public void setControlEncoding(String encoding) { + _controlEncoding = encoding; + } + + + /** + * @return The character encoding used to communicate over the + * control connection. + */ + public String getControlEncoding() { + return _controlEncoding; + } + + + /*** + * Adds a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.addProtocolCommandListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.removeProtocolCommandListener(listener); + } + + + /*** + * Closes the control connection to the FTP server and sets to null + * some internal data so that the memory may be reclaimed by the + * garbage collector. The reply text and code information from the + * last command is voided so that the memory it used may be reclaimed. + * Also sets {@link #_controlInput_} and {@link #_controlOutput_} to null. + *

+ * @exception IOException If an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + _controlInput_ = null; + _controlOutput_ = null; + _newReplyString = false; + _replyString = null; + } + + + /*** + * Sends an FTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The text representation of the FTP command to send. + * @param args The arguments to the FTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command, String args) throws IOException + { + String message; + + __commandBuffer.setLength(0); + __commandBuffer.append(command); + + if (args != null) + { + __commandBuffer.append(' '); + __commandBuffer.append(args); + } + __commandBuffer.append(SocketClient.NETASCII_EOL); + + try{ + _controlOutput_.write(message = __commandBuffer.toString()); + _controlOutput_.flush(); + } + catch (SocketException e) + { + if (!isConnected() || !socketIsConnected(_socket_)) + { + throw new FTPConnectionClosedException("Connection unexpectedly closed."); + } + else + { + throw e; + } + } + + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireCommandSent(command, message); + + __getReply(); + return _replyCode; + } + + /** + * Checks if the socket is connected + * + * @param socket + * @return true if connected + */ + private boolean socketIsConnected(Socket socket) + { + if (socket == null) + { + return false; + } + + return socket.isConnected(); + + } + + /*** + * Sends an FTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The FTPCommand constant corresponding to the FTP command + * to send. + * @param args The arguments to the FTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command, String args) throws IOException + { + return sendCommand(FTPCommand._commands[command], args); + } + + + /*** + * Sends an FTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The text representation of the FTP command to send. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Sends an FTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The FTPCommand constant corresponding to the FTP command + * to send. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Returns the integer value of the reply code of the last FTP reply. + * You will usually only use this method after you connect to the + * FTP server to check that the connection was successful since + * connect is of type void. + *

+ * @return The integer value of the reply code of the last FTP reply. + ***/ + public int getReplyCode() + { + return _replyCode; + } + + /*** + * Fetches a reply from the FTP server and returns the integer reply + * code. After calling this method, the actual reply text can be accessed + * from either calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. Only use this + * method if you are implementing your own FTP client or if you need to + * fetch a secondary response from the FTP server. + *

+ * @return The integer value of the reply code of the fetched FTP reply. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while receiving the + * server reply. + ***/ + public int getReply() throws IOException + { + __getReply(); + return _replyCode; + } + + + /*** + * Returns the lines of text from the last FTP server response as an array + * of strings, one entry per line. The end of line markers of each are + * stripped from each line. + *

+ * @return The lines of text from the last FTP response as an array. + ***/ + public String[] getReplyStrings() + { + String[] lines; + lines = new String[_replyLines.size()]; + _replyLines.addAll(Arrays.asList(lines)); + return lines; + } + + /*** + * Returns the entire text of the last FTP server response exactly + * as it was received, including all end of line markers in NETASCII + * format. + *

+ * @return The entire text from the last FTP response as a String. + ***/ + public String getReplyString() + { + StringBuilder buffer; + + if (!_newReplyString) { + return _replyString; + } + + buffer = new StringBuilder(256); + + for (String line : _replyLines) { + buffer.append(line); + buffer.append(SocketClient.NETASCII_EOL); + } + + _newReplyString = false; + + return (_replyString = buffer.toString()); + } + + + /*** + * A convenience method to send the FTP USER command to the server, + * receive the reply, and return the reply code. + *

+ * @param username The username to login under. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int user(String username) throws IOException + { + return sendCommand(FTPCommand.USER, username); + } + + /** + * A convenience method to send the FTP PASS command to the server, + * receive the reply, and return the reply code. + * @param password The plain text password of the username being logged into. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int pass(String password) throws IOException + { + return sendCommand(FTPCommand.PASS, password); + } + + /*** + * A convenience method to send the FTP ACCT command to the server, + * receive the reply, and return the reply code. + *

+ * @param account The account name to access. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int acct(String account) throws IOException + { + return sendCommand(FTPCommand.ACCT, account); + } + + + /*** + * A convenience method to send the FTP ABOR command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int abor() throws IOException + { + return sendCommand(FTPCommand.ABOR); + } + + /*** + * A convenience method to send the FTP CWD command to the server, + * receive the reply, and return the reply code. + *

+ * @param directory The new working directory. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int cwd(String directory) throws IOException + { + return sendCommand(FTPCommand.CWD, directory); + } + + /*** + * A convenience method to send the FTP CDUP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int cdup() throws IOException + { + return sendCommand(FTPCommand.CDUP); + } + + /*** + * A convenience method to send the FTP QUIT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int quit() throws IOException + { + return sendCommand(FTPCommand.QUIT); + } + + /*** + * A convenience method to send the FTP REIN command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rein() throws IOException + { + return sendCommand(FTPCommand.REIN); + } + + /*** + * A convenience method to send the FTP SMNT command to the server, + * receive the reply, and return the reply code. + *

+ * @param dir The directory name. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int smnt(String dir) throws IOException + { + return sendCommand(FTPCommand.SMNT, dir); + } + + /*** + * A convenience method to send the FTP PORT command to the server, + * receive the reply, and return the reply code. + *

+ * @param host The host owning the port. + * @param port The new port. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int port(InetAddress host, int port) throws IOException + { + int num; + StringBuffer info = new StringBuffer(24); + + info.append(host.getHostAddress().replace('.', ',')); + num = port >>> 8; + info.append(','); + info.append(num); + info.append(','); + num = port & 0xff; + info.append(num); + + return sendCommand(FTPCommand.PORT, info.toString()); + } + + /*** + * A convenience method to send the FTP PASV command to the server, + * receive the reply, and return the reply code. Remember, it's up + * to you to interpret the reply string containing the host/port + * information. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int pasv() throws IOException + { + return sendCommand(FTPCommand.PASV); + } + + /** + * A convenience method to send the FTP TYPE command for text files + * to the server, receive the reply, and return the reply code. + * @param fileType The type of the file (one of the FILE_TYPE + * constants). + * @param formatOrByteSize The format of the file (one of the + * _FORMAT constants. In the case of + * LOCAL_FILE_TYPE, the byte size. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int type(int fileType, int formatOrByteSize) throws IOException + { + StringBuffer arg = new StringBuffer(); + + arg.append(__modes.charAt(fileType)); + arg.append(' '); + if (fileType == LOCAL_FILE_TYPE) + arg.append(formatOrByteSize); + else + arg.append(__modes.charAt(formatOrByteSize)); + + return sendCommand(FTPCommand.TYPE, arg.toString()); + } + + + /** + * A convenience method to send the FTP TYPE command to the server, + * receive the reply, and return the reply code. + *

+ * @param fileType The type of the file (one of the FILE_TYPE + * constants). + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int type(int fileType) throws IOException + { + return sendCommand(FTPCommand.TYPE, + __modes.substring(fileType, fileType + 1)); + } + + /*** + * A convenience method to send the FTP STRU command to the server, + * receive the reply, and return the reply code. + *

+ * @param structure The structure of the file (one of the + * _STRUCTURE constants). + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stru(int structure) throws IOException + { + return sendCommand(FTPCommand.STRU, + __modes.substring(structure, structure + 1)); + } + + /*** + * A convenience method to send the FTP MODE command to the server, + * receive the reply, and return the reply code. + *

+ * @param mode The transfer mode to use (one of the + * TRANSFER_MODE constants). + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int mode(int mode) throws IOException + { + return sendCommand(FTPCommand.MODE, + __modes.substring(mode, mode + 1)); + } + + /*** + * A convenience method to send the FTP RETR command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname of the file to retrieve. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int retr(String pathname) throws IOException + { + return sendCommand(FTPCommand.RETR, pathname); + } + + /*** + * A convenience method to send the FTP STOR command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to use for the file when stored at + * the remote end of the transfer. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stor(String pathname) throws IOException + { + return sendCommand(FTPCommand.STOR, pathname); + } + + /*** + * A convenience method to send the FTP STOU command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stou() throws IOException + { + return sendCommand(FTPCommand.STOU); + } + + /*** + * A convenience method to send the FTP STOU command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + * @param pathname The base pathname to use for the file when stored at + * the remote end of the transfer. Some FTP servers + * require this. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int stou(String pathname) throws IOException + { + return sendCommand(FTPCommand.STOU, pathname); + } + + /*** + * A convenience method to send the FTP APPE command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to use for the file when stored at + * the remote end of the transfer. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int appe(String pathname) throws IOException + { + return sendCommand(FTPCommand.APPE, pathname); + } + + /*** + * A convenience method to send the FTP ALLO command to the server, + * receive the reply, and return the reply code. + *

+ * @param bytes The number of bytes to allocate. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int allo(int bytes) throws IOException + { + return sendCommand(FTPCommand.ALLO, Integer.toString(bytes)); + } + + /*** + * A convenience method to send the FTP ALLO command to the server, + * receive the reply, and return the reply code. + *

+ * @param bytes The number of bytes to allocate. + * @param recordSize The size of a record. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int allo(int bytes, int recordSize) throws IOException + { + return sendCommand(FTPCommand.ALLO, Integer.toString(bytes) + " R " + + Integer.toString(recordSize)); + } + + /*** + * A convenience method to send the FTP REST command to the server, + * receive the reply, and return the reply code. + *

+ * @param marker The marker at which to restart a transfer. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rest(String marker) throws IOException + { + return sendCommand(FTPCommand.REST, marker); + } + + + /** + * @since 2.0 + **/ + public int mdtm(String file) throws IOException + { + return sendCommand(FTPCommand.MDTM, file); + } + + /*** + * A convenience method to send the FTP RNFR command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname to rename from. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rnfr(String pathname) throws IOException + { + return sendCommand(FTPCommand.RNFR, pathname); + } + + /*** + * A convenience method to send the FTP RNTO command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname to rename to + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rnto(String pathname) throws IOException + { + return sendCommand(FTPCommand.RNTO, pathname); + } + + /*** + * A convenience method to send the FTP DELE command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname to delete. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int dele(String pathname) throws IOException + { + return sendCommand(FTPCommand.DELE, pathname); + } + + /*** + * A convenience method to send the FTP RMD command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname of the directory to remove. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rmd(String pathname) throws IOException + { + return sendCommand(FTPCommand.RMD, pathname); + } + + /*** + * A convenience method to send the FTP MKD command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname of the new directory to create. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int mkd(String pathname) throws IOException + { + return sendCommand(FTPCommand.MKD, pathname); + } + + /*** + * A convenience method to send the FTP PWD command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int pwd() throws IOException + { + return sendCommand(FTPCommand.PWD); + } + + /*** + * A convenience method to send the FTP LIST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int list() throws IOException + { + return sendCommand(FTPCommand.LIST); + } + + /*** + * A convenience method to send the FTP LIST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to list. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int list(String pathname) throws IOException + { + return sendCommand(FTPCommand.LIST, pathname); + } + + /*** + * A convenience method to send the FTP NLST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int nlst() throws IOException + { + return sendCommand(FTPCommand.NLST); + } + + /*** + * A convenience method to send the FTP NLST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to list. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int nlst(String pathname) throws IOException + { + return sendCommand(FTPCommand.NLST, pathname); + } + + /*** + * A convenience method to send the FTP SITE command to the server, + * receive the reply, and return the reply code. + *

+ * @param parameters The site parameters to send. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int site(String parameters) throws IOException + { + return sendCommand(FTPCommand.SITE, parameters); + } + + /*** + * A convenience method to send the FTP SYST command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int syst() throws IOException + { + return sendCommand(FTPCommand.SYST); + } + + /*** + * A convenience method to send the FTP STAT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat() throws IOException + { + return sendCommand(FTPCommand.STAT); + } + + /*** + * A convenience method to send the FTP STAT command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname A pathname to list. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat(String pathname) throws IOException + { + return sendCommand(FTPCommand.STAT, pathname); + } + + /*** + * A convenience method to send the FTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help() throws IOException + { + return sendCommand(FTPCommand.HELP); + } + + /*** + * A convenience method to send the FTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @param command The command name on which to request help. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help(String command) throws IOException + { + return sendCommand(FTPCommand.HELP, command); + } + + /*** + * A convenience method to send the FTP NOOP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int noop() throws IOException + { + return sendCommand(FTPCommand.NOOP); + } + + /** + * Return whether strict multiline parsing is enabled, as per RFX 959, section 4.2. + * @return True if strict, false if lenient + * @since 2.0 + */ + public boolean isStrictMultilineParsing() { + return strictMultilineParsing; + } + + /** + * Set strict multiline parsing. + * @param strictMultilineParsing + * @since 2.0 + */ + public void setStrictMultilineParsing(boolean strictMultilineParsing) { + this.strictMultilineParsing = strictMultilineParsing; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/ftp/FTPClient.class b/org/apache/commons/net/ftp/FTPClient.class new file mode 100644 index 0000000..60ac793 Binary files /dev/null and b/org/apache/commons/net/ftp/FTPClient.class differ diff --git a/org/apache/commons/net/ftp/FTPClient.java b/org/apache/commons/net/ftp/FTPClient.java new file mode 100644 index 0000000..9a2c459 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPClient.java @@ -0,0 +1,2447 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory; +import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory; +import org.apache.commons.net.ftp.parser.ParserInitializationException; +import org.apache.commons.net.io.CopyStreamEvent; +import org.apache.commons.net.io.CopyStreamException; +import org.apache.commons.net.io.FromNetASCIIInputStream; +import org.apache.commons.net.io.ToNetASCIIOutputStream; +import org.apache.commons.net.io.Util; + +/*** + * FTPClient encapsulates all the functionality necessary to store and + * retrieve files from an FTP server. This class takes care of all + * low level details of interacting with an FTP server and provides + * a convenient higher level interface. As with all classes derived + * from {@link org.apache.commons.net.SocketClient}, + * you must first connect to the server with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before doing anything, and finally + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * after you're completely finished interacting with the server. + * Then you need to check the FTP reply code to see if the connection + * was successful. For example: + *

+ *    boolean error = false;
+ *    try {
+ *      int reply;
+ *      ftp.connect("ftp.foobar.com");
+ *      System.out.println("Connected to " + server + ".");
+ *      System.out.print(ftp.getReplyString());
+ *
+ *      // After connection attempt, you should check the reply code to verify
+ *      // success.
+ *      reply = ftp.getReplyCode();
+ *
+ *      if(!FTPReply.isPositiveCompletion(reply)) {
+ *        ftp.disconnect();
+ *        System.err.println("FTP server refused connection.");
+ *        System.exit(1);
+ *      }
+ *      ... // transfer files
+ *      ftp.logout();
+ *    } catch(IOException e) {
+ *      error = true;
+ *      e.printStackTrace();
+ *    } finally {
+ *      if(ftp.isConnected()) {
+ *        try {
+ *          ftp.disconnect();
+ *        } catch(IOException ioe) {
+ *          // do nothing
+ *        }
+ *      }
+ *      System.exit(error ? 1 : 0);
+ *    }
+ * 
+ *

+ * Immediately after connecting is the only real time you need to check the + * reply code (because connect is of type void). The convention for all the + * FTP command methods in FTPClient is such that they either return a + * boolean value or some other value. + * The boolean methods return true on a successful completion reply from + * the FTP server and false on a reply resulting in an error condition or + * failure. The methods returning a value other than boolean return a value + * containing the higher level data produced by the FTP command, or null if a + * reply resulted in an error condition or failure. If you want to access + * the exact FTP reply code causing a success or failure, you must call + * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after + * a success or failure. + *

+ * The default settings for FTPClient are for it to use + * FTP.ASCII_FILE_TYPE , + * FTP.NON_PRINT_TEXT_FORMAT , + * FTP.STREAM_TRANSFER_MODE , and + * FTP.FILE_STRUCTURE . The only file types directly supported + * are FTP.ASCII_FILE_TYPE and + * FTP.BINARY_FILE_TYPE . Because there are at least 4 + * different EBCDIC encodings, we have opted not to provide direct support + * for EBCDIC. To transfer EBCDIC and other unsupported file types you + * must create your own filter InputStreams and OutputStreams and wrap + * them around the streams returned or required by the FTPClient methods. + * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII} + * filter streams to provide transparent handling of ASCII files. We will + * consider incorporating EBCDIC support if there is enough demand. + *

+ * FTP.NON_PRINT_TEXT_FORMAT , + * FTP.STREAM_TRANSFER_MODE , and + * FTP.FILE_STRUCTURE are the only supported formats, + * transfer modes, and file structures. + *

+ * Because the handling of sockets on different platforms can differ + * significantly, the FTPClient automatically issues a new PORT command + * prior to every transfer requiring that the server connect to the client's + * data port. This ensures identical problem-free behavior on Windows, Unix, + * and Macintosh platforms. Additionally, it relieves programmers from + * having to issue the PORT command themselves and dealing with platform + * dependent issues. + *

+ * Additionally, for security purposes, all data connections to the + * client are verified to ensure that they originated from the intended + * party (host and port). If a data connection is initiated by an unexpected + * party, the command will close the socket and throw an IOException. You + * may disable this behavior with + * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}. + *

+ * You should keep in mind that the FTP server may choose to prematurely + * close a connection if the client has been idle for longer than a + * given time period (usually 900 seconds). The FTPClient class will detect a + * premature FTP server connection closing when it receives a + * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } + * response to a command. + * When that occurs, the FTP class method encountering that reply will throw + * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * . + * FTPConnectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * , you must disconnect the connection with + * {@link #disconnect disconnect() } to properly clean up the + * system resources used by FTPClient. Before disconnecting, you may check the + * last reply code and text with + * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode }, + * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString }, + * and + * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}. + * You may avoid server disconnections while the client is idle by + * periodicaly sending NOOP commands to the server. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ * Listing API Examples + * Both paged and unpaged examples of directory listings are available, + * as follows: + *

+ * Unpaged (whole list) access, using a parser accessible by auto-detect: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ * Paged access, using a parser not accessible by auto-detect. The class + * defined in the first parameter of initateListParsing should be derived + * from org.apache.commons.net.FTPFileEntryParser: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine =
+ *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ * Paged access, using a parser accessible by auto-detect: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine = f.initiateListParsing(directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ * For examples of using FTPClient on servers whose directory listings + *

see {@link FTPClientConfig FTPClientConfig}. + *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @see FTP + * @see FTPConnectionClosedException + * @see FTPFileEntryParser + * @see FTPFileEntryParserFactory + * @see DefaultFTPFileEntryParserFactory + * @see FTPClientConfig + * + * @see org.apache.commons.net.MalformedServerReplyException + **/ +public class FTPClient extends FTP +implements Configurable +{ + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between the client (local) and server and that the server + * should connect to the client's data port to initiate a data transfer. + * This is the default data connection mode when and FTPClient instance + * is created. + ***/ + public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0; + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between two remote servers and that the server + * the client is connected to should connect to the other server's + * data port to initiate a data transfer. + ***/ + public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1; + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between the client (local) and server and that the server + * is in passive mode, requiring the client to connect to the + * server's data port to initiate a transfer. + ***/ + public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2; + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between two remote servers and that the server + * the client is connected to is in passive mode, requiring the other + * server to connect to the first server's data port to initiate a data + * transfer. + ***/ + public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3; + + private int __dataConnectionMode, __dataTimeout; + private int __passivePort; + private String __passiveHost; + private int __fileType, __fileFormat, __fileStructure, __fileTransferMode; + private boolean __remoteVerificationEnabled; + private long __restartOffset; + private FTPFileEntryParserFactory __parserFactory; + private int __bufferSize; + private boolean __listHiddenFiles; + + // __systemName is a cached value that should not be referenced directly + // except when assigned in getSystemName and __initDefaults. + private String __systemName; + + // __entryParser is a cached value that should not be referenced directly + // except when assigned in listFiles(String, String) and __initDefaults. + private FTPFileEntryParser __entryParser; + + private FTPClientConfig __configuration; + + /** Pattern for PASV mode responses */ + private static String __parms = "\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}"; + private static java.util.regex.Pattern __parms_pat; + static { + __parms_pat = java.util.regex.Pattern.compile(__parms); + } + + /*** + * Default FTPClient constructor. Creates a new FTPClient instance + * with the data connection mode set to + * ACTIVE_LOCAL_DATA_CONNECTION_MODE , the file type + * set to FTP.ASCII_FILE_TYPE , the + * file format set to FTP.NON_PRINT_TEXT_FORMAT , + * the file structure set to FTP.FILE_STRUCTURE , and + * the transfer mode set to FTP.STREAM_TRANSFER_MODE . + ***/ + public FTPClient() + { + __initDefaults(); + __dataTimeout = -1; + __remoteVerificationEnabled = true; + __parserFactory = new DefaultFTPFileEntryParserFactory(); + __configuration = null; + __listHiddenFiles = false; + } + + + private void __initDefaults() + { + __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; + __passiveHost = null; + __passivePort = -1; + __fileType = FTP.ASCII_FILE_TYPE; + __fileStructure = FTP.FILE_STRUCTURE; + __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; + __fileTransferMode = FTP.STREAM_TRANSFER_MODE; + __restartOffset = 0; + __systemName = null; + __entryParser = null; + __bufferSize = Util.DEFAULT_COPY_BUFFER_SIZE; + } + + private String __parsePathname(String reply) + { + int begin, end; + + begin = reply.indexOf('"') + 1; + end = reply.indexOf('"', begin); + + return reply.substring(begin, end); + } + + + private void __parsePassiveModeReply(String reply) + throws MalformedServerReplyException + { + java.util.regex.Matcher m = __parms_pat.matcher(reply); + if (!m.find()) { + throw new MalformedServerReplyException( + "Could not parse passive host information.\nServer Reply: " + reply); + } + reply = m.group(); + String parts[] = m.group().split(","); + + __passiveHost = parts[0] + '.' + parts[1] + '.' + parts[2] + '.' + parts[3]; + + try + { + int oct1 = Integer.parseInt(parts[4]); + int oct2 = Integer.parseInt(parts[5]); + __passivePort = (oct1 << 8) | oct2; + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse passive host information.\nServer Reply: " + reply); + } + + } + + private boolean __storeFile(int command, String remote, InputStream local) + throws IOException + { + OutputStream output; + Socket socket; + + if ((socket = _openDataConnection_(command, remote)) == null) + return false; + + output = new BufferedOutputStream(socket.getOutputStream(), + getBufferSize() + ); + if (__fileType == ASCII_FILE_TYPE) + output = new ToNetASCIIOutputStream(output); + // Treat everything else as binary for now + try + { + Util.copyStream(local, output, getBufferSize(), + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, + false); + } + catch (IOException e) + { + try + { + socket.close(); + } + catch (IOException f) + {} + throw e; + } + output.close(); + socket.close(); + return completePendingCommand(); + } + + private OutputStream __storeFileStream(int command, String remote) + throws IOException + { + OutputStream output; + Socket socket; + + if ((socket = _openDataConnection_(command, remote)) == null) + return null; + + output = socket.getOutputStream(); + if (__fileType == ASCII_FILE_TYPE) { + // We buffer ascii transfers because the buffering has to + // be interposed between ToNetASCIIOutputSream and the underlying + // socket output stream. We don't buffer binary transfers + // because we don't want to impose a buffering policy on the + // programmer if possible. Programmers can decide on their + // own if they want to wrap the SocketOutputStream we return + // for file types other than ASCII. + output = new BufferedOutputStream(output, + getBufferSize()); + output = new ToNetASCIIOutputStream(output); + + } + return new org.apache.commons.net.io.SocketOutputStream(socket, output); + } + + + /** + * Establishes a data connection with the FTP server, returning + * a Socket for the connection if successful. If a restart + * offset has been set with {@link #setRestartOffset(long)}, + * a REST command is issued to the server with the offset as + * an argument before establishing the data connection. Active + * mode connections also cause a local PORT command to be issued. + *

+ * @param command The text representation of the FTP command to send. + * @param arg The arguments to the FTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return A Socket corresponding to the established data connection. + * Null is returned if an FTP protocol error is reported at + * any point during the establishment and initialization of + * the connection. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + protected Socket _openDataConnection_(int command, String arg) + throws IOException + { + Socket socket; + + if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE && + __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) + return null; + + if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) + { + ServerSocket server; + server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); + + if (!FTPReply.isPositiveCompletion(port(getLocalAddress(), + server.getLocalPort()))) + { + server.close(); + return null; + } + + if ((__restartOffset > 0) && !restart(__restartOffset)) + { + server.close(); + return null; + } + + if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) + { + server.close(); + return null; + } + + // For now, let's just use the data timeout value for waiting for + // the data connection. It may be desirable to let this be a + // separately configurable value. In any case, we really want + // to allow preventing the accept from blocking indefinitely. + if (__dataTimeout >= 0) + server.setSoTimeout(__dataTimeout); + try { + socket = server.accept(); + } finally { + server.close(); + } + } + else + { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE + + if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) + return null; + + __parsePassiveModeReply(_replyLines.get(_replyLines.size() - 1)); + + socket = _socketFactory_.createSocket(__passiveHost, __passivePort); + if ((__restartOffset > 0) && !restart(__restartOffset)) + { + socket.close(); + return null; + } + + if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) + { + socket.close(); + return null; + } + } + + if (__remoteVerificationEnabled && !verifyRemote(socket)) + { + InetAddress host1, host2; + + host1 = socket.getInetAddress(); + host2 = getRemoteAddress(); + + socket.close(); + + throw new IOException( + "Host attempting data connection " + host1.getHostAddress() + + " is not same as server " + host2.getHostAddress()); + } + + if (__dataTimeout >= 0) + socket.setSoTimeout(__dataTimeout); + + return socket; + } + + + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + __initDefaults(); + } + + + /*** + * Sets the timeout in milliseconds to use when reading from the + * data connection. This timeout will be set immediately after + * opening the data connection. + *

+ * @param timeout The default timeout in milliseconds that is used when + * opening a data connection socket. + ***/ + public void setDataTimeout(int timeout) + { + __dataTimeout = timeout; + } + + /** + * set the factory used for parser creation to the supplied factory object. + * + * @param parserFactory + * factory object used to create FTPFileEntryParsers + * + * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + */ + public void setParserFactory(FTPFileEntryParserFactory parserFactory) { + __parserFactory = parserFactory; + } + + + /*** + * Closes the connection to the FTP server and restores + * connection parameters to the default values. + *

+ * @exception IOException If an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + __initDefaults(); + } + + + /*** + * Enable or disable verification that the remote host taking part + * of a data connection is the same as the host to which the control + * connection is attached. The default is for verification to be + * enabled. You may set this value at any time, whether the + * FTPClient is currently connected or not. + *

+ * @param enable True to enable verification, false to disable verification. + ***/ + public void setRemoteVerificationEnabled(boolean enable) + { + __remoteVerificationEnabled = enable; + } + + /*** + * Return whether or not verification of the remote host participating + * in data connections is enabled. The default behavior is for + * verification to be enabled. + *

+ * @return True if verification is enabled, false if not. + ***/ + public boolean isRemoteVerificationEnabled() + { + return __remoteVerificationEnabled; + } + + /*** + * Login to the FTP server using the provided username and password. + *

+ * @param username The username to login under. + * @param password The password to use. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean login(String username, String password) throws IOException + { + user(username); + + if (FTPReply.isPositiveCompletion(_replyCode)) + return true; + + // If we get here, we either have an error code, or an intermmediate + // reply requesting password. + if (!FTPReply.isPositiveIntermediate(_replyCode)) + return false; + + return FTPReply.isPositiveCompletion(pass(password)); + } + + + /*** + * Login to the FTP server using the provided username, password, + * and account. If no account is required by the server, only + * the username and password, the account information is not used. + *

+ * @param username The username to login under. + * @param password The password to use. + * @param account The account to use. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean login(String username, String password, String account) + throws IOException + { + user(username); + + if (FTPReply.isPositiveCompletion(_replyCode)) + return true; + + // If we get here, we either have an error code, or an intermmediate + // reply requesting password. + if (!FTPReply.isPositiveIntermediate(_replyCode)) + return false; + + pass(password); + + if (FTPReply.isPositiveCompletion(_replyCode)) + return true; + + if (!FTPReply.isPositiveIntermediate(_replyCode)) + return false; + + return FTPReply.isPositiveCompletion(acct(account)); + } + + /*** + * Logout of the FTP server by sending the QUIT command. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean logout() throws IOException + { + return FTPReply.isPositiveCompletion(quit()); + } + + + /*** + * Change the current working directory of the FTP session. + *

+ * @param pathname The new current working directory. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean changeWorkingDirectory(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(cwd(pathname)); + } + + + /*** + * Change to the parent directory of the current working directory. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean changeToParentDirectory() throws IOException + { + return FTPReply.isPositiveCompletion(cdup()); + } + + + /*** + * Issue the FTP SMNT command. + *

+ * @param pathname The pathname to mount. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean structureMount(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(smnt(pathname)); + } + + /*** + * Reinitialize the FTP session. Not all FTP servers support this + * command, which issues the FTP REIN command. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + boolean reinitialize() throws IOException + { + rein(); + + if (FTPReply.isPositiveCompletion(_replyCode) || + (FTPReply.isPositivePreliminary(_replyCode) && + FTPReply.isPositiveCompletion(getReply()))) + { + + __initDefaults(); + + return true; + } + + return false; + } + + + /*** + * Set the current data connection mode to + * ACTIVE_LOCAL_DATA_CONNECTION_MODE. No communication + * with the FTP server is conducted, but this causes all future data + * transfers to require the FTP server to connect to the client's + * data port. Additionally, to accommodate differences between socket + * implementations on different platforms, this method causes the + * client to issue a PORT command before every data transfer. + ***/ + public void enterLocalActiveMode() + { + __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; + __passiveHost = null; + __passivePort = -1; + } + + + /*** + * Set the current data connection mode to + * PASSIVE_LOCAL_DATA_CONNECTION_MODE . Use this + * method only for data transfers between the client and server. + * This method causes a PASV command to be issued to the server + * before the opening of every data connection, telling the server to + * open a data port to which the client will connect to conduct + * data transfers. The FTPClient will stay in + * PASSIVE_LOCAL_DATA_CONNECTION_MODE until the + * mode is changed by calling some other method such as + * {@link #enterLocalActiveMode enterLocalActiveMode() } + ***/ + public void enterLocalPassiveMode() + { + __dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE; + // These will be set when just before a data connection is opened + // in _openDataConnection_() + __passiveHost = null; + __passivePort = -1; + } + + + /*** + * Set the current data connection mode to + * ACTIVE_REMOTE_DATA_CONNECTION . Use this method only + * for server to server data transfers. This method issues a PORT + * command to the server, indicating the other server and port to which + * it should connect for data transfers. You must call this method + * before EVERY server to server transfer attempt. The FTPClient will + * NOT automatically continue to issue PORT commands. You also + * must remember to call + * {@link #enterLocalActiveMode enterLocalActiveMode() } if you + * wish to return to the normal data connection mode. + *

+ * @param host The passive mode server accepting connections for data + * transfers. + * @param port The passive mode server's data port. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean enterRemoteActiveMode(InetAddress host, int port) + throws IOException + { + if (FTPReply.isPositiveCompletion(port(host, port))) + { + __dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE; + __passiveHost = null; + __passivePort = -1; + return true; + } + return false; + } + + /*** + * Set the current data connection mode to + * PASSIVE_REMOTE_DATA_CONNECTION_MODE . Use this + * method only for server to server data transfers. + * This method issues a PASV command to the server, telling it to + * open a data port to which the active server will connect to conduct + * data transfers. You must call this method + * before EVERY server to server transfer attempt. The FTPClient will + * NOT automatically continue to issue PASV commands. You also + * must remember to call + * {@link #enterLocalActiveMode enterLocalActiveMode() } if you + * wish to return to the normal data connection mode. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean enterRemotePassiveMode() throws IOException + { + if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) + return false; + + __dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE; + __parsePassiveModeReply(_replyLines.get(0)); + + return true; + } + + /*** + * Returns the hostname or IP address (in the form of a string) returned + * by the server when entering passive mode. If not in passive mode, + * returns null. This method only returns a valid value AFTER a + * data connection has been opened after a call to + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + * This is because FTPClient sends a PASV command to the server only + * just before opening a data connection, and not when you call + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + *

+ * @return The passive host name if in passive mode, otherwise null. + ***/ + public String getPassiveHost() + { + return __passiveHost; + } + + /*** + * If in passive mode, returns the data port of the passive host. + * This method only returns a valid value AFTER a + * data connection has been opened after a call to + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + * This is because FTPClient sends a PASV command to the server only + * just before opening a data connection, and not when you call + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + *

+ * @return The data port of the passive server. If not in passive + * mode, undefined. + ***/ + public int getPassivePort() + { + return __passivePort; + } + + + /*** + * Returns the current data connection mode (one of the + * _DATA_CONNECTION_MODE constants. + *

+ * @return The current data connection mode (one of the + * _DATA_CONNECTION_MODE constants. + ***/ + public int getDataConnectionMode() + { + return __dataConnectionMode; + } + + + /*** + * Sets the file type to be transferred. This should be one of + * FTP.ASCII_FILE_TYPE , FTP.BINARY_FILE_TYPE, + * etc. The file type only needs to be set when you want to change the + * type. After changing it, the new type stays in effect until you change + * it again. The default file type is FTP.ASCII_FILE_TYPE + * if this method is never called. + *

+ * @param fileType The _FILE_TYPE constant indcating the + * type of file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileType(int fileType) throws IOException + { + if (FTPReply.isPositiveCompletion(type(fileType))) + { + __fileType = fileType; + __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; + return true; + } + return false; + } + + + /*** + * Sets the file type to be transferred and the format. The type should be + * one of FTP.ASCII_FILE_TYPE , + * FTP.BINARY_FILE_TYPE , etc. The file type only needs to + * be set when you want to change the type. After changing it, the new + * type stays in effect until you change it again. The default file type + * is FTP.ASCII_FILE_TYPE if this method is never called. + * The format should be one of the FTP class TEXT_FORMAT + * constants, or if the type is FTP.LOCAL_FILE_TYPE , the + * format should be the byte size for that type. The default format + * is FTP.NON_PRINT_TEXT_FORMAT if this method is never + * called. + *

+ * @param fileType The _FILE_TYPE constant indcating the + * type of file. + * @param formatOrByteSize The format of the file (one of the + * _FORMAT constants. In the case of + * LOCAL_FILE_TYPE, the byte size. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileType(int fileType, int formatOrByteSize) + throws IOException + { + if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) + { + __fileType = fileType; + __fileFormat = formatOrByteSize; + return true; + } + return false; + } + + + /*** + * Sets the file structure. The default structure is + * FTP.FILE_STRUCTURE if this method is never called. + *

+ * @param structure The structure of the file (one of the FTP class + * _STRUCTURE constants). + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileStructure(int structure) throws IOException + { + if (FTPReply.isPositiveCompletion(stru(structure))) + { + __fileStructure = structure; + return true; + } + return false; + } + + + /*** + * Sets the transfer mode. The default transfer mode + * FTP.STREAM_TRANSFER_MODE if this method is never called. + *

+ * @param mode The new transfer mode to use (one of the FTP class + * _TRANSFER_MODE constants). + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileTransferMode(int mode) throws IOException + { + if (FTPReply.isPositiveCompletion(mode(mode))) + { + __fileTransferMode = mode; + return true; + } + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to retrieve a given file from + * the other server. + *

+ * @param filename The name of the file to retrieve. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteRetrieve(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(retr(filename)); + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to store a file on + * the other server using the given filename. The other server must + * have had a remoteRetrieve issued to it by another + * FTPClient. + *

+ * @param filename The name to call the file that is to be stored. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteStore(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stor(filename)); + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to store a file on + * the other server using a unique filename based on the given filename. + * The other server must have had a remoteRetrieve issued + * to it by another FTPClient. + *

+ * @param filename The name on which to base the filename of the file + * that is to be stored. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteStoreUnique(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stou(filename)); + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to store a file on + * the other server using a unique filename. + * The other server must have had a remoteRetrieve issued + * to it by another FTPClient. Many FTP servers require that a base + * filename be given from which the unique filename can be derived. For + * those servers use the other version of remoteStoreUnique + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteStoreUnique() throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stou()); + return false; + } + + // For server to server transfers + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to append to a given file on + * the other server. The other server must have had a + * remoteRetrieve issued to it by another FTPClient. + *

+ * @param filename The name of the file to be appended to, or if the + * file does not exist, the name to call the file being stored. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteAppend(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stor(filename)); + return false; + } + + /*** + * There are a few FTPClient methods that do not complete the + * entire sequence of FTP commands to complete a transaction. These + * commands require some action by the programmer after the reception + * of a positive intermediate command. After the programmer's code + * completes its actions, it must call this method to receive + * the completion reply from the server and verify the success of the + * entire transaction. + *

+ * For example, + *

+     * InputStream input;
+     * OutputStream output;
+     * input  = new FileInputStream("foobaz.txt");
+     * output = ftp.storeFileStream("foobar.txt")
+     * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
+     *     input.close();
+     *     output.close();
+     *     ftp.logout();
+     *     ftp.disconnect();
+     *     System.err.println("File transfer failed.");
+     *     System.exit(1);
+     * }
+     * Util.copyStream(input, output);
+     * input.close();
+     * output.close();
+     * // Must call completePendingCommand() to finish command.
+     * if(!ftp.completePendingCommand()) {
+     *     ftp.logout();
+     *     ftp.disconnect();
+     *     System.err.println("File transfer failed.");
+     *     System.exit(1);
+     * }
+     * 
+ *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean completePendingCommand() throws IOException + { + return FTPReply.isPositiveCompletion(getReply()); + } + + + /*** + * Retrieves a named file from the server and writes it to the given + * OutputStream. This method does NOT close the given OutputStream. + * If the current file type is ASCII, line separators in the file are + * converted to the local representation. + *

+ * @param remote The name of the remote file. + * @param local The local OutputStream to which to write the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean retrieveFile(String remote, OutputStream local) + throws IOException + { + InputStream input; + Socket socket; + + if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) + return false; + + input = new BufferedInputStream(socket.getInputStream(), + getBufferSize()); + if (__fileType == ASCII_FILE_TYPE) + input = new FromNetASCIIInputStream(input); + // Treat everything else as binary for now + try + { + Util.copyStream(input, local, getBufferSize(), + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, + false); + } + catch (IOException e) + { + try + { + socket.close(); + } + catch (IOException f) + {} + throw e; + } + socket.close(); + return completePendingCommand(); + } + + /*** + * Returns an InputStream from which a named file from the server + * can be read. If the current file type is ASCII, the returned + * InputStream will convert line separators in the file to + * the local representation. You must close the InputStream when you + * finish reading from it. The InputStream itself will take care of + * closing the parent data connection socket upon being closed. To + * finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name of the remote file. + * @return An InputStream from which the remote file can be read. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public InputStream retrieveFileStream(String remote) throws IOException + { + InputStream input; + Socket socket; + + if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) + return null; + + input = socket.getInputStream(); + if (__fileType == ASCII_FILE_TYPE) { + // We buffer ascii transfers because the buffering has to + // be interposed between FromNetASCIIOutputSream and the underlying + // socket input stream. We don't buffer binary transfers + // because we don't want to impose a buffering policy on the + // programmer if possible. Programmers can decide on their + // own if they want to wrap the SocketInputStream we return + // for file types other than ASCII. + input = new BufferedInputStream(input, + getBufferSize()); + input = new FromNetASCIIInputStream(input); + } + return new org.apache.commons.net.io.SocketInputStream(socket, input); + } + + + /*** + * Stores a file on the server using the given name and taking input + * from the given InputStream. This method does NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param remote The name to give the remote file. + * @param local The local InputStream from which to read the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean storeFile(String remote, InputStream local) + throws IOException + { + return __storeFile(FTPCommand.STOR, remote, local); + } + + + /*** + * Returns an OutputStream through which data can be written to store + * a file on the server using the given name. If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name to give the remote file. + * @return An OutputStream through which the remote file can be written. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public OutputStream storeFileStream(String remote) throws IOException + { + return __storeFileStream(FTPCommand.STOR, remote); + } + + /*** + * Appends to a file on the server with the given name, taking input + * from the given InputStream. This method does NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param remote The name of the remote file. + * @param local The local InputStream from which to read the data to + * be appended to the remote file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean appendFile(String remote, InputStream local) + throws IOException + { + return __storeFile(FTPCommand.APPE, remote, local); + } + + /*** + * Returns an OutputStream through which data can be written to append + * to a file on the server with the given name. If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name of the remote file. + * @return An OutputStream through which the remote file can be appended. + * If the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public OutputStream appendFileStream(String remote) throws IOException + { + return __storeFileStream(FTPCommand.APPE, remote); + } + + /*** + * Stores a file on the server using a unique name derived from the + * given name and taking input + * from the given InputStream. This method does NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param remote The name on which to base the unique name given to + * the remote file. + * @param local The local InputStream from which to read the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean storeUniqueFile(String remote, InputStream local) + throws IOException + { + return __storeFile(FTPCommand.STOU, remote, local); + } + + + /*** + * Returns an OutputStream through which data can be written to store + * a file on the server using a unique name derived from the given name. + * If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name on which to base the unique name given to + * the remote file. + * @return An OutputStream through which the remote file can be written. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public OutputStream storeUniqueFileStream(String remote) throws IOException + { + return __storeFileStream(FTPCommand.STOU, remote); + } + + /** + * Stores a file on the server using a unique name assigned by the + * server and taking input from the given InputStream. This method does + * NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param local The local InputStream from which to read the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public boolean storeUniqueFile(InputStream local) throws IOException + { + return __storeFile(FTPCommand.STOU, null, local); + } + + /** + * Returns an OutputStream through which data can be written to store + * a file on the server using a unique name assigned by the server. + * If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @return An OutputStream through which the remote file can be written. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public OutputStream storeUniqueFileStream() throws IOException + { + return __storeFileStream(FTPCommand.STOU, null); + } + + /*** + * Reserve a number of bytes on the server for the next file transfer. + *

+ * @param bytes The number of bytes which the server should allocate. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean allocate(int bytes) throws IOException + { + return FTPReply.isPositiveCompletion(allo(bytes)); + } + + + /** + * Reserve space on the server for the next file transfer. + *

+ * @param bytes The number of bytes which the server should allocate. + * @param recordSize The size of a file record. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public boolean allocate(int bytes, int recordSize) throws IOException + { + return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); + } + + + /*** + * Restart a STREAM_TRANSFER_MODE file transfer starting + * from the given offset. This will only work on FTP servers supporting + * the REST comand for the stream transfer mode. However, most FTP + * servers support this. Any subsequent file transfer will start + * reading or writing the remote file from the indicated offset. + *

+ * @param offset The offset into the remote file at which to start the + * next file transfer. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + private boolean restart(long offset) throws IOException + { + __restartOffset = 0; + return FTPReply.isPositiveIntermediate(rest(Long.toString(offset))); + } + + /*** + * Sets the restart offset. The restart command is sent to the server + * only before sending the file transfer command. When this is done, + * the restart marker is reset to zero. + *

+ * @param offset The offset into the remote file at which to start the + * next file transfer. This must be a value greater than or + * equal to zero. + ***/ + public void setRestartOffset(long offset) + { + if (offset >= 0) + __restartOffset = offset; + } + + /*** + * Fetches the restart offset. + *

+ * @return offset The offset into the remote file at which to start the + * next file transfer. + ***/ + public long getRestartOffset() + { + return __restartOffset; + } + + + + /*** + * Renames a remote file. + *

+ * @param from The name of the remote file to rename. + * @param to The new name of the remote file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean rename(String from, String to) throws IOException + { + if (!FTPReply.isPositiveIntermediate(rnfr(from))) + return false; + + return FTPReply.isPositiveCompletion(rnto(to)); + } + + + /*** + * Abort a transfer in progress. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean abort() throws IOException + { + return FTPReply.isPositiveCompletion(abor()); + } + + /*** + * Deletes a file on the FTP server. + *

+ * @param pathname The pathname of the file to be deleted. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean deleteFile(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(dele(pathname)); + } + + + /*** + * Removes a directory on the FTP server (if empty). + *

+ * @param pathname The pathname of the directory to remove. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean removeDirectory(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(rmd(pathname)); + } + + + /*** + * Creates a new subdirectory on the FTP server in the current directory + * (if a relative pathname is given) or where specified (if an absolute + * pathname is given). + *

+ * @param pathname The pathname of the directory to create. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean makeDirectory(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(mkd(pathname)); + } + + + /*** + * Returns the pathname of the current working directory. + *

+ * @return The pathname of the current working directory. If it cannot + * be obtained, returns null. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String printWorkingDirectory() throws IOException + { + if (pwd() != FTPReply.PATHNAME_CREATED) + return null; + + return __parsePathname(_replyLines.get( _replyLines.size() - 1)); + } + + + /** + * Send a site specific command. + * @param arguments The site specific command and arguments. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public boolean sendSiteCommand(String arguments) throws IOException + { + return FTPReply.isPositiveCompletion(site(arguments)); + } + + + /*** + * Fetches the system type name from the server and returns the string. + * This value is cached for the duration of the connection after the + * first call to this method. In other words, only the first time + * that you invoke this method will it issue a SYST command to the + * FTP server. FTPClient will remember the value and return the + * cached value until a call to disconnect. + *

+ * @return The system type name obtained from the server. null if the + * information could not be obtained. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String getSystemName() throws IOException + { + //if (syst() == FTPReply.NAME_SYSTEM_TYPE) + // Technically, we should expect a NAME_SYSTEM_TYPE response, but + // in practice FTP servers deviate, so we soften the condition to + // a positive completion. + if (__systemName == null && FTPReply.isPositiveCompletion(syst())) + __systemName = _replyLines.get(_replyLines.size() - 1).substring(4); + + return __systemName; + } + + + /*** + * Fetches the system help information from the server and returns the + * full string. + *

+ * @return The system help string obtained from the server. null if the + * information could not be obtained. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String listHelp() throws IOException + { + if (FTPReply.isPositiveCompletion(help())) + return getReplyString(); + return null; + } + + + /** + * Fetches the help information for a given command from the server and + * returns the full string. + * @param command The command on which to ask for help. + * @return The command help string obtained from the server. null if the + * information could not be obtained. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public String listHelp(String command) throws IOException + { + if (FTPReply.isPositiveCompletion(help(command))) + return getReplyString(); + return null; + } + + + /*** + * Sends a NOOP command to the FTP server. This is useful for preventing + * server timeouts. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean sendNoOp() throws IOException + { + return FTPReply.isPositiveCompletion(noop()); + } + + + /*** + * Obtain a list of filenames in a directory (or just the name of a given + * file, which is not particularly useful). This information is obtained + * through the NLST command. If the given pathname is a directory and + * contains no files, a zero length array is returned only + * if the FTP server returned a positive completion code, otherwise + * null is returned (the FTP server returned a 550 error No files found.). + * If the directory is not empty, an array of filenames in the directory is + * returned. If the pathname corresponds + * to a file, only that file will be listed. The server may or may not + * expand glob expressions. + *

+ * @param pathname The file or directory to list. + * @return The list of filenames contained in the given path. null if + * the list could not be obtained. If there are no filenames in + * the directory, a zero-length array is returned. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String[] listNames(String pathname) throws IOException + { + String line; + Socket socket; + BufferedReader reader; + ArrayList results; + + if ((socket = _openDataConnection_(FTPCommand.NLST, pathname)) == null) + return null; + + reader = + new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); + + results = new ArrayList(); + while ((line = reader.readLine()) != null) + results.add(line); + + reader.close(); + socket.close(); + + if (completePendingCommand()) + { + String[] names = new String[ results.size() ]; + return results.toArray(names); + } + + return null; + } + + + /*** + * Obtain a list of filenames in the current working directory + * This information is obtained through the NLST command. If the current + * directory contains no files, a zero length array is returned only + * if the FTP server returned a positive completion code, otherwise, + * null is returned (the FTP server returned a 550 error No files found.). + * If the directory is not empty, an array of filenames in the directory is + * returned. + *

+ * @return The list of filenames contained in the current working + * directory. null if the list could not be obtained. + * If there are no filenames in the directory, a zero-length array + * is returned. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String[] listNames() throws IOException + { + return listNames(null); + } + + + + /** + * Using the default system autodetect mechanism, obtain a + * list of file information for the current working directory + * or for just a single file. + *

+ * This information is obtained through the LIST command. The contents of + * the returned array is determined by the FTPFileEntryParser + * used. + *

+ * @param pathname The file or directory to list. Since the server may + * or may not expand glob expressions, using them here + * is not recommended and may well cause this method to + * fail. + * + * @return The list of file information contained in the given path in + * the format determined by the autodetection mechanism + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection + * as a result of the client being idle or some other + * reason causing the server to send FTP reply code 421. + * This exception may be caught either as an IOException + * or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply + * from the server. + * @exception ParserInitializationException + * Thrown if the parserKey parameter cannot be + * resolved by the selected parser factory. + * In the DefaultFTPEntryParserFactory, this will + * happen when parserKey is neither + * the fully qualified class name of a class + * implementing the interface + * org.apache.commons.net.ftp.FTPFileEntryParser + * nor a string containing one of the recognized keys + * mapping to such a parser or if class loader + * security issues prevent its being loaded. + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.FTPFileEntryParser + */ + public FTPFile[] listFiles(String pathname) + throws IOException + { + String key = null; + FTPListParseEngine engine = + initiateListParsing(key, pathname); + return engine.getFiles(); + + } + /** + * Using the default system autodetect mechanism, obtain a + * list of file information for the current working directory. + *

+ * This information is obtained through the LIST command. The contents of + * the returned array is determined by the FTPFileEntryParser + * used. + *

+ * @return The list of file information contained in the current directory + * in the format determined by the autodetection mechanism. + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection + * as a result of the client being idle or some other + * reason causing the server to send FTP reply code 421. + * This exception may be caught either as an IOException + * or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply + * from the server. + * @exception ParserInitializationException + * Thrown if the parserKey parameter cannot be + * resolved by the selected parser factory. + * In the DefaultFTPEntryParserFactory, this will + * happen when parserKey is neither + * the fully qualified class name of a class + * implementing the interface + * org.apache.commons.net.ftp.FTPFileEntryParser + * nor a string containing one of the recognized keys + * mapping to such a parser or if class loader + * security issues prevent its being loaded. + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.FTPFileEntryParser + */ + public FTPFile[] listFiles() + throws IOException + { + return listFiles((String) null); + } + + /** + * Using the default autodetect mechanism, initialize an FTPListParseEngine + * object containing a raw file information for the current working + * directory on the server + * This information is obtained through the LIST command. This object + * is then capable of being iterated to return a sequence of FTPFile + * objects with information filled in by the + * FTPFileEntryParser used. + *

+ * This method differs from using the listFiles() methods in that + * expensive FTPFile objects are not created until needed which may be + * an advantage on large lists. + * + * @return A FTPListParseEngine object that holds the raw information and + * is capable of providing parsed FTPFile objects, one for each file + * containing information contained in the given path in the format + * determined by the parser parameter. Null will be + * returned if a data connection cannot be opened. If the current working + * directory contains no files, an empty array will be the return. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @exception ParserInitializationException + * Thrown if the autodetect mechanism cannot + * resolve the type of system we are connected with. + * @see FTPListParseEngine + */ + public FTPListParseEngine initiateListParsing() + throws IOException + { + return initiateListParsing((String) null); + } + + /** + * Using the default autodetect mechanism, initialize an FTPListParseEngine + * object containing a raw file information for the supplied directory. + * This information is obtained through the LIST command. This object + * is then capable of being iterated to return a sequence of FTPFile + * objects with information filled in by the + * FTPFileEntryParser used. + *

+ * The server may or may not expand glob expressions. You should avoid + * using glob expressions because the return format for glob listings + * differs from server to server and will likely cause this method to fail. + *

+ * This method differs from using the listFiles() methods in that + * expensive FTPFile objects are not created until needed which may be + * an advantage on large lists. + *

+ *

+     *    FTPClient f=FTPClient();
+     *    f.connect(server);
+     *    f.login(username, password);
+     *    FTPListParseEngine engine = f.initiateListParsing(directory);
+     *
+     *    while (engine.hasNext()) {
+     *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+     *       //do whatever you want with these files, display them, etc.
+     *       //expensive FTPFile objects not created until needed.
+     *    }
+     * 
+ * + * @return A FTPListParseEngine object that holds the raw information and + * is capable of providing parsed FTPFile objects, one for each file + * containing information contained in the given path in the format + * determined by the parser parameter. Null will be + * returned if a data connection cannot be opened. If the current working + * directory contains no files, an empty array will be the return. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @exception ParserInitializationException + * Thrown if the autodetect mechanism cannot + * resolve the type of system we are connected with. + * @see FTPListParseEngine + */ + public FTPListParseEngine initiateListParsing( + String pathname) + throws IOException + { + String key = null; + return initiateListParsing(key, pathname); + } + + /** + * Using the supplied parser key, initialize an FTPListParseEngine + * object containing a raw file information for the supplied directory. + * This information is obtained through the LIST command. This object + * is then capable of being iterated to return a sequence of FTPFile + * objects with information filled in by the + * FTPFileEntryParser used. + *

+ * The server may or may not expand glob expressions. You should avoid + * using glob expressions because the return format for glob listings + * differs from server to server and will likely cause this method to fail. + *

+ * This method differs from using the listFiles() methods in that + * expensive FTPFile objects are not created until needed which may be + * an advantage on large lists. + * + * @param parserKey A string representing a designated code or fully-qualified + * class name of an FTPFileEntryParser that should be + * used to parse each server file listing. + * + * @return A FTPListParseEngine object that holds the raw information and + * is capable of providing parsed FTPFile objects, one for each file + * containing information contained in the given path in the format + * determined by the parser parameter. Null will be + * returned if a data connection cannot be opened. If the current working + * directory contains no files, an empty array will be the return. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @exception ParserInitializationException + * Thrown if the parserKey parameter cannot be + * resolved by the selected parser factory. + * In the DefaultFTPEntryParserFactory, this will + * happen when parserKey is neither + * the fully qualified class name of a class + * implementing the interface + * org.apache.commons.net.ftp.FTPFileEntryParser + * nor a string containing one of the recognized keys + * mapping to such a parser or if class loader + * security issues prevent its being loaded. + * @see FTPListParseEngine + */ + public FTPListParseEngine initiateListParsing( + String parserKey, String pathname) + throws IOException + { + // We cache the value to avoid creation of a new object every + // time a file listing is generated. + if(__entryParser == null) { + if (null != parserKey) { + // if a parser key was supplied in the parameters, + // use that to create the paraser + __entryParser = + __parserFactory.createFileEntryParser(parserKey); + + } else { + // if no parserKey was supplied, check for a configuration + // in the params, and if non-null, use that. + if (null != __configuration) { + __entryParser = + __parserFactory.createFileEntryParser(__configuration); + } else { + // if a parserKey hasn't been supplied, and a configuration + // hasn't been supplied, then autodetect by calling + // the SYST command and use that to choose the parser. + __entryParser = + __parserFactory.createFileEntryParser(getSystemName()); + } + } + } + + return initiateListParsing(__entryParser, pathname); + + } + + + /** + * private method through which all listFiles() and + * initiateListParsing methods pass once a parser is determined. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @see FTPListParseEngine + */ + private FTPListParseEngine initiateListParsing( + FTPFileEntryParser parser, String pathname) + throws IOException + { + Socket socket; + + FTPListParseEngine engine = new FTPListParseEngine(parser); + + if ((socket = _openDataConnection_(FTPCommand.LIST, getListArguments(pathname))) == null) + { + return engine; + } + + + try { + engine.readServerList(socket.getInputStream(), getControlEncoding()); + } + finally { + socket.close(); + } + + completePendingCommand(); + return engine; + } + + /** + * @since 2.0 + */ + protected String getListArguments(String pathname) { + if (getListHiddenFiles()) + { + StringBuffer sb = new StringBuffer(pathname.length() + 3); + sb.append("-a "); + sb.append(pathname); + return sb.toString(); + } + + return pathname; + } + + + /*** + * Issue the FTP STAT command to the server. + *

+ * @return The status information returned by the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String getStatus() throws IOException + { + if (FTPReply.isPositiveCompletion(stat())) + return getReplyString(); + return null; + } + + + /*** + * Issue the FTP STAT command to the server for a given pathname. This + * should produce a listing of the file or directory. + *

+ * @return The status information returned by the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String getStatus(String pathname) throws IOException + { + if (FTPReply.isPositiveCompletion(stat(pathname))) + return getReplyString(); + return null; + } + + + /** + * Issue the FTP MDTM command (not supported by all servers to retrieve the last + * modification time of a file. The modification string should be in the + * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in + * GMT, but not all FTP servers honour this. + * + * @param pathname The file path to query. + * @return A string representing the last file modification time in YYYYMMDDhhmmss format. + * @throws IOException if an I/O error occurs. + * @since 2.0 + */ + public String getModificationTime(String pathname) throws IOException { + if (FTPReply.isPositiveCompletion(mdtm(pathname))) + return getReplyString(); + return null; + } + + + /** + * Set the internal buffer size. + * + * @param bufSize The size of the buffer + */ + public void setBufferSize(int bufSize) { + __bufferSize = bufSize; + } + + /** + * Retrieve the current internal buffer size. + * @return The current buffer size. + */ + public int getBufferSize() { + return __bufferSize; + } + + + /** + * Implementation of the {@link Configurable Configurable} interface. + * In the case of this class, configuring merely makes the config object available for the + * factory methods that construct parsers. + * @param config {@link FTPClientConfig FTPClientConfig} object used to + * provide non-standard configurations to the parser. + * @since 1.4 + */ + public void configure(FTPClientConfig config) { + this.__configuration = config; + } + + /** + * You can set this to true if you would like to get hidden files when {@link #listFiles} too. + * A LIST -a will be issued to the ftp server. + * It depends on your ftp server if you need to call this method, also dont expect to get rid + * of hidden files if you call this method with "false". + * + * @param listHiddenFiles true if hidden files should be listed + * @since 2.0 + */ + public void setListHiddenFiles(boolean listHiddenFiles) { + this.__listHiddenFiles = listHiddenFiles; + } + + /** + * @see #setListHiddenFiles(boolean) + * @return the current state + * @since 2.0 + */ + public boolean getListHiddenFiles() { + return this.__listHiddenFiles; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/ftp/FTPClientConfig.class b/org/apache/commons/net/ftp/FTPClientConfig.class new file mode 100644 index 0000000..b42c8ee Binary files /dev/null and b/org/apache/commons/net/ftp/FTPClientConfig.class differ diff --git a/org/apache/commons/net/ftp/FTPClientConfig.java b/org/apache/commons/net/ftp/FTPClientConfig.java new file mode 100644 index 0000000..450eddc --- /dev/null +++ b/org/apache/commons/net/ftp/FTPClientConfig.java @@ -0,0 +1,580 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.text.DateFormatSymbols; +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; + +/** + *

+ * This class implements an alternate means of configuring the + * {@link org.apache.commons.net.ftp.FTPClient FTPClient} object and + * also subordinate objects which it uses. Any class implementing the + * {@link org.apache.commons.net.ftp.Configurable Configurable } + * interface can be configured by this object. + *

+ * In particular this class was designed primarily to support configuration + * of FTP servers which express file timestamps in formats and languages + * other than those for the US locale, which although it is the most common + * is not universal. Unfortunately, nothing in the FTP spec allows this to + * be determined in an automated way, so manual configuration such as this + * is necessary. + *

+ * This functionality was designed to allow existing clients to work exactly + * as before without requiring use of this component. This component should + * only need to be explicitly invoked by the user of this package for problem + * cases that previous implementations could not solve. + *

+ *

Examples of use of FTPClientConfig

+ * Use cases: + * You are trying to access a server that + * + *

+ * Unpaged (whole list) access on a UNIX server that uses French month names + * but uses the "standard" MMM d yyyy date formatting + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
+ *    conf.setServerLanguageCode("fr");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ *

+ * Paged access on a UNIX server that uses Danish month names + * and "European" date formatting in Denmark's time zone, when you + * are in some other time zone. + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
+ *    conf.setServerLanguageCode("da");
+ *    conf.setDefaultDateFormat("d MMM yyyy");
+ *    conf.setRecentDateFormat("d MMM HH:mm");
+ *    conf.setTimeZoneId("Europe/Copenhagen");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine =
+ *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ *

+ * Unpaged (whole list) access on a VMS server that uses month names + * in a language not {@link #getSupportedLanguageCodes() supported} by the system. + * but uses the "standard" MMM d yyyy date formatting + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS);
+ *    conf.setShortMonthNames(
+ *        "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ *

+ * Unpaged (whole list) access on a Windows-NT server in a different time zone. + * (Note, since the NT Format uses numeric date formatting, language issues + * are irrelevant here). + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
+ *    conf.setTimeZoneId("America/Denver");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ * Unpaged (whole list) access on a Windows-NT server in a different time zone + * but which has been configured to use a unix-style listing format. + *
+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
+ *    conf.setTimeZoneId("America/Denver");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ * @since 1.4 + * @see org.apache.commons.net.ftp.Configurable + * @see org.apache.commons.net.ftp.FTPClient + * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) + * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl + */ +public class FTPClientConfig +{ + + /** + * Identifier by which a unix-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_UNIX = "UNIX"; + + /** + * Identifier by which a vms-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_VMS = "VMS"; + + /** + * Identifier by which a WindowsNT-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_NT = "WINDOWS"; + + /** + * Identifier by which an OS/2-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_OS2 = "OS/2"; + + /** + * Identifier by which an OS/400-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_OS400 = "OS/400"; + + /** + * Identifier by which an AS/400-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_AS400 = "AS/400"; + + /** + * Identifier by which an MVS-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_MVS = "MVS"; + + /** + * Some servers return an "UNKNOWN Type: L8" message + * in response to the SYST command. We set these to be a Unix-type system. + * This may happen if the ftpd in question was compiled without system + * information. + * + * NET-230 - Updated to be UPPERCASE so that the check done in + * createFileEntryParser will succeed. + * + * @since 1.5 + */ + public static final String SYST_L8 = "TYPE: L8"; + + /** + * Identifier by which an Netware-based ftp server is known throughout + * the commons-net ftp system. + * + * @since 1.5 + */ + public static final String SYST_NETWARE = "NETWARE"; + + private final String serverSystemKey; + private String defaultDateFormatStr = null; + private String recentDateFormatStr = null; + private boolean lenientFutureDates = false; + private String serverLanguageCode = null; + private String shortMonthNames = null; + private String serverTimeZoneId = null; + + + /** + * The main constructor for an FTPClientConfig object + * @param systemKey key representing system type of the server being + * connected to. See {@link #getServerSystemKey() serverSystemKey} + */ + public FTPClientConfig(String systemKey) { + this.serverSystemKey = systemKey; + } + + /** + * Convenience constructor mainly for use in testing. + * Constructs a UNIX configuration. + */ + public FTPClientConfig() { + this(SYST_UNIX); + } + + /** + * Constructor which allows setting of all member fields + * @param systemKey key representing system type of the server being + * connected to. See + * {@link #getServerSystemKey() serverSystemKey} + * @param defaultDateFormatStr See + * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} + * @param recentDateFormatStr See + * {@link #setRecentDateFormatStr(String) recentDateFormatStr} + * @param serverLanguageCode See + * {@link #setServerLanguageCode(String) serverLanguageCode} + * @param shortMonthNames See + * {@link #setShortMonthNames(String) shortMonthNames} + * @param serverTimeZoneId See + * {@link #setServerTimeZoneId(String) serverTimeZoneId} + */ + public FTPClientConfig(String systemKey, + String defaultDateFormatStr, + String recentDateFormatStr, + String serverLanguageCode, + String shortMonthNames, + String serverTimeZoneId) + { + this(systemKey); + this.defaultDateFormatStr = defaultDateFormatStr; + this.recentDateFormatStr = recentDateFormatStr; + this.serverLanguageCode = serverLanguageCode; + this.shortMonthNames = shortMonthNames; + this.serverTimeZoneId = serverTimeZoneId; + } + + private static Map LANGUAGE_CODE_MAP = new TreeMap(); + static { + + // if there are other commonly used month name encodings which + // correspond to particular locales, please add them here. + + + + // many locales code short names for months as all three letters + // these we handle simply. + LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); + LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); + LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); + LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish + LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese + LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish + LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish + LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian + LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch + LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian + LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian + LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian + LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak + LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian + + + // some don't + LANGUAGE_CODE_MAP.put("fr", + "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french + + } + + /** + * Getter for the serverSystemKey property. This property + * specifies the general type of server to which the client connects. + * Should be either one of the FTPClientConfig.SYST_* codes + * or else the fully qualified class name of a parser implementing both + * the FTPFileEntryParser and Configurable + * interfaces. + * @return Returns the serverSystemKey property. + */ + public String getServerSystemKey() { + return serverSystemKey; + } + + /** + * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} + * property. + * @return Returns the defaultDateFormatStr property. + */ + public String getDefaultDateFormatStr() { + return defaultDateFormatStr; + } + + /** + * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. + * @return Returns the recentDateFormatStr property. + */ + + public String getRecentDateFormatStr() { + return recentDateFormatStr; + } + + /** + * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. + * @return Returns the serverTimeZoneId property. + */ + public String getServerTimeZoneId() { + return serverTimeZoneId; + } + + /** + *

+ * getter for the {@link #setShortMonthNames(String) shortMonthNames} + * property. + *

+ * @return Returns the shortMonthNames. + */ + public String getShortMonthNames() { + return shortMonthNames; + } + + /** + *

+ * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. + *

+ * @return Returns the serverLanguageCode property. + */ + public String getServerLanguageCode() { + return serverLanguageCode; + } + + /** + *

+ * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. + *

+ * @return Returns the lenientFutureDates. + * @since 1.5 + */ + public boolean isLenientFutureDates() { + return lenientFutureDates; + } + /** + *

+ * setter for the defaultDateFormatStr property. This property + * specifies the main date format that will be used by a parser configured + * by this configuration to parse file timestamps. If this is not + * specified, such a parser will use as a default value, the most commonly + * used format which will be in as used in en_US locales. + *

+ * This should be in the format described for + * java.text.SimpleDateFormat. + * property. + *

+ * @param defaultDateFormatStr The defaultDateFormatStr to set. + */ + public void setDefaultDateFormatStr(String defaultDateFormatStr) { + this.defaultDateFormatStr = defaultDateFormatStr; + } + + /** + *

+ * setter for the recentDateFormatStr property. This property + * specifies a secondary date format that will be used by a parser + * configured by this configuration to parse file timestamps, typically + * those less than a year old. If this is not specified, such a parser + * will not attempt to parse using an alternate format. + *

+ * This is used primarily in unix-based systems. + *

+ * This should be in the format described for + * java.text.SimpleDateFormat. + *

+ * @param recentDateFormatStr The recentDateFormatStr to set. + */ + public void setRecentDateFormatStr(String recentDateFormatStr) { + this.recentDateFormatStr = recentDateFormatStr; + } + + /** + *

+ * setter for the lenientFutureDates property. This boolean property + * (default: false) only has meaning when a + * {@link #setRecentDateFormatStr(String) recentDateFormatStr} property + * has been set. In that case, if this property is set true, then the + * parser, when it encounters a listing parseable with the recent date + * format, will only consider a date to belong to the previous year if + * it is more than one day in the future. This will allow all + * out-of-synch situations (whether based on "slop" - i.e. servers simply + * out of synch with one another or because of time zone differences - + * but in the latter case it is highly recommended to use the + * {@link #setServerTimeZoneId(String) serverTimeZoneId} property + * instead) to resolve correctly. + *

+ * This is used primarily in unix-based systems. + *

+ * @param lenientFutureDates set true to compensate for out-of-synch + * conditions. + */ + public void setLenientFutureDates(boolean lenientFutureDates) { + this.lenientFutureDates = lenientFutureDates; + } + /** + *

+ * setter for the serverTimeZoneId property. This property + * allows a time zone to be specified corresponding to that known to be + * used by an FTP server in file listings. This might be particularly + * useful to clients such as Ant that try to use these timestamps for + * dependency checking. + *

+ * This should be one of the identifiers used by + * java.util.TimeZone to refer to time zones, for example, + * America/Chicago or Asia/Rangoon. + *

+ * @param serverTimeZoneId The serverTimeZoneId to set. + */ + public void setServerTimeZoneId(String serverTimeZoneId) { + this.serverTimeZoneId = serverTimeZoneId; + } + + /** + *

+ * setter for the shortMonthNames property. + * This property allows the user to specify a set of month names + * used by the server that is different from those that may be + * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} + * property. + *

+ * This should be a string containing twelve strings each composed of + * three characters, delimited by pipe (|) characters. Currently, + * only 8-bit ASCII characters are known to be supported. For example, + * a set of month names used by a hypothetical Icelandic FTP server might + * conceivably be specified as + * "jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des". + *

+ * @param shortMonthNames The value to set to the shortMonthNames property. + */ + public void setShortMonthNames(String shortMonthNames) { + this.shortMonthNames = shortMonthNames; + } + + /** + *

+ * setter for the serverLanguageCode property. This property allows + * user to specify a + * + * two-letter ISO-639 language code that will be used to + * configure the set of month names used by the file timestamp parser. + * If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} + * is specified, parsing will assume English month names, which may or + * may not be significant, depending on whether the date format(s) + * specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} + * and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using + * numeric or alphabetic month names. + *

+ *

If the code supplied is not supported here, en_US + * month names will be used. We are supporting here those language + * codes which, when a java.util.Locale is constucted + * using it, and a java.text.SimpleDateFormat is + * constructed using that Locale, the array returned by the + * SimpleDateFormat's getShortMonths() method consists + * solely of three 8-bit ASCII character strings. Additionally, + * languages which do not meet this requirement are included if a + * common alternative set of short month names is known to be used. + * This means that users who can tell us of additional such encodings + * may get them added to the list of supported languages by contacting + * the jakarta-commons-net team. + *

+ *

+ * Please note that this attribute will NOT be used to determine a + * locale-based date format for the language. + * Experience has shown that many if not most FTP servers outside the + * United States employ the standard en_US date format + * orderings of MMM d yyyy and MMM d HH:mm + * and attempting to deduce this automatically here would cause more + * problems than it would solve. The date format must be changed + * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or + * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. + *

+ * @param serverLanguageCode The value to set to the serverLanguageCode property. + */ + public void setServerLanguageCode(String serverLanguageCode) { + this.serverLanguageCode = serverLanguageCode; + } + + /** + * Looks up the supplied language code in the internally maintained table of + * language codes. Returns a DateFormatSymbols object configured with + * short month names corresponding to the code. If there is no corresponding + * entry in the table, the object returned will be that for + * Locale.US + * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} + * @return a DateFormatSymbols object configured with short month names + * corresponding to the supplied code, or with month names for + * Locale.US if there is no corresponding entry in the internal + * table. + */ + public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) + { + Object lang = LANGUAGE_CODE_MAP.get(languageCode); + if (lang != null) { + if (lang instanceof Locale) { + return new DateFormatSymbols((Locale) lang); + } else if (lang instanceof String){ + return getDateFormatSymbols((String) lang); + } + } + return new DateFormatSymbols(Locale.US); + } + + /** + * Returns a DateFormatSymbols object configured with short month names + * as in the supplied string + * @param shortmonths This should be as described in + * {@link #setShortMonthNames(String) shortMonthNames} + * @return a DateFormatSymbols object configured with short month names + * as in the supplied string + */ + public static DateFormatSymbols getDateFormatSymbols(String shortmonths) + { + String[] months = splitShortMonthString(shortmonths); + DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); + dfs.setShortMonths(months); + return dfs; + } + + private static String[] splitShortMonthString(String shortmonths) { + StringTokenizer st = new StringTokenizer(shortmonths, "|"); + int monthcnt = st.countTokens(); + if (12 != monthcnt) { + throw new IllegalArgumentException( + "expecting a pipe-delimited string containing 12 tokens"); + } + String[] months = new String[13]; + int pos = 0; + while(st.hasMoreTokens()) { + months[pos++] = st.nextToken(); + } + months[pos]=""; + return months; + } + + /** + * Returns a Collection of all the language codes currently supported + * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} + * for a functional descrption of language codes within this system. + * + * @return a Collection of all the language codes currently supported + * by this class + */ + public static Collection getSupportedLanguageCodes() { + return LANGUAGE_CODE_MAP.keySet(); + } + + +} diff --git a/org/apache/commons/net/ftp/FTPCommand.class b/org/apache/commons/net/ftp/FTPCommand.class new file mode 100644 index 0000000..15c59a3 Binary files /dev/null and b/org/apache/commons/net/ftp/FTPCommand.class differ diff --git a/org/apache/commons/net/ftp/FTPCommand.java b/org/apache/commons/net/ftp/FTPCommand.java new file mode 100644 index 0000000..d016dff --- /dev/null +++ b/org/apache/commons/net/ftp/FTPCommand.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +/*** + * FTPCommand stores a set of constants for FTP command codes. To interpret + * the meaning of the codes, familiarity with RFC 959 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 959. For those who think in terms of the actual FTP commands, + * a set of constants such as {@link #USER USER } are provided + * where the constant name is the same as the FTP command. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FTPCommand +{ + + + public static final int USER = 0; + public static final int PASS = 1; + public static final int ACCT = 2; + public static final int CWD = 3; + public static final int CDUP = 4; + public static final int SMNT = 5; + public static final int REIN = 6; + public static final int QUIT = 7; + public static final int PORT = 8; + public static final int PASV = 9; + public static final int TYPE = 10; + public static final int STRU = 11; + public static final int MODE = 12; + public static final int RETR = 13; + public static final int STOR = 14; + public static final int STOU = 15; + public static final int APPE = 16; + public static final int ALLO = 17; + public static final int REST = 18; + public static final int RNFR = 19; + public static final int RNTO = 20; + public static final int ABOR = 21; + public static final int DELE = 22; + public static final int RMD = 23; + public static final int MKD = 24; + public static final int PWD = 25; + public static final int LIST = 26; + public static final int NLST = 27; + public static final int SITE = 28; + public static final int SYST = 29; + public static final int STAT = 30; + public static final int HELP = 31; + public static final int NOOP = 32; + /** @since 2.0 */ + public static final int MDTM = 33; + + public static final int USERNAME = USER; + public static final int PASSWORD = PASS; + public static final int ACCOUNT = ACCT; + public static final int CHANGE_WORKING_DIRECTORY = CWD; + public static final int CHANGE_TO_PARENT_DIRECTORY = CDUP; + public static final int STRUCTURE_MOUNT = SMNT; + public static final int REINITIALIZE = REIN; + public static final int LOGOUT = QUIT; + public static final int DATA_PORT = PORT; + public static final int PASSIVE = PASV; + public static final int REPRESENTATION_TYPE = TYPE; + public static final int FILE_STRUCTURE = STRU; + public static final int TRANSFER_MODE = MODE; + public static final int RETRIEVE = RETR; + public static final int STORE = STOR; + public static final int STORE_UNIQUE = STOU; + public static final int APPEND = APPE; + public static final int ALLOCATE = ALLO; + public static final int RESTART = REST; + public static final int RENAME_FROM = RNFR; + public static final int RENAME_TO = RNTO; + public static final int ABORT = ABOR; + public static final int DELETE = DELE; + public static final int REMOVE_DIRECTORY = RMD; + public static final int MAKE_DIRECTORY = MKD; + public static final int PRINT_WORKING_DIRECTORY = PWD; + // public static final int LIST = LIST; + public static final int NAME_LIST = NLST; + public static final int SITE_PARAMETERS = SITE; + public static final int SYSTEM = SYST; + public static final int STATUS = STAT; + //public static final int HELP = HELP; + //public static final int NOOP = NOOP; + /** @since 2.0 */ + public static final int MOD_TIME = MDTM; + + // Cannot be instantiated + private FTPCommand() + {} + + static final String[] _commands = { + "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", + "PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", + "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", + "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP" + }; + + /** + * Retrieve the FTP protocol command string corresponding to a specified + * command code. + *

+ * @param command The command code. + * @return The FTP protcol command string corresponding to a specified + * command code. + */ + public static final String getCommand(int command) + { + return _commands[command]; + } +} diff --git a/org/apache/commons/net/ftp/FTPConnectionClosedException.class b/org/apache/commons/net/ftp/FTPConnectionClosedException.class new file mode 100644 index 0000000..38004cb Binary files /dev/null and b/org/apache/commons/net/ftp/FTPConnectionClosedException.class differ diff --git a/org/apache/commons/net/ftp/FTPConnectionClosedException.java b/org/apache/commons/net/ftp/FTPConnectionClosedException.java new file mode 100644 index 0000000..3eccbf4 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPConnectionClosedException.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.IOException; + +/*** + * FTPConnectionClosedException is used to indicate the premature or + * unexpected closing of an FTP connection resulting from a + * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } + * response (FTP reply code 421) to a + * failed FTP command. This exception is derived from IOException and + * therefore may be caught either as an IOException or specifically as an + * FTPConnectionClosedException. + *

+ *

+ * @author Daniel F. Savarese + * @see FTP + * @see FTPClient + ***/ + +public class FTPConnectionClosedException extends IOException +{ + + /*** Constructs a FTPConnectionClosedException with no message ***/ + public FTPConnectionClosedException() + { + super(); + } + + /*** + * Constructs a FTPConnectionClosedException with a specified message. + *

+ * @param message The message explaining the reason for the exception. + ***/ + public FTPConnectionClosedException(String message) + { + super(message); + } + +} diff --git a/org/apache/commons/net/ftp/FTPFile.class b/org/apache/commons/net/ftp/FTPFile.class new file mode 100644 index 0000000..6cb7744 Binary files /dev/null and b/org/apache/commons/net/ftp/FTPFile.class differ diff --git a/org/apache/commons/net/ftp/FTPFile.java b/org/apache/commons/net/ftp/FTPFile.java new file mode 100644 index 0000000..dd67904 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPFile.java @@ -0,0 +1,392 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.Serializable; +import java.util.Calendar; + +/*** + * The FTPFile class is used to represent information about files stored + * on an FTP server. Because there is no standard representation for + * file information on FTP servers, it may not always be possible to + * extract all the information that can be represented by FTPFile, or + * it may even be possible to extract more information. In cases where + * more information can be extracted, you will want to subclass FTPFile + * and implement your own {@link org.apache.commons.net.ftp.FTPFileListParser} + * to extract the information. + * However, most FTP servers return file information in a format that + * can be completely parsed by + * {@link org.apache.commons.net.ftp.DefaultFTPFileListParser} + * and stored in FTPFile. + *

+ *

+ * @author Daniel F. Savarese + * @see FTPFileListParser + * @see DefaultFTPFileListParser + * @see FTPClient#listFiles + ***/ + +public class FTPFile implements Serializable +{ + /** A constant indicating an FTPFile is a file. ***/ + public static final int FILE_TYPE = 0; + /** A constant indicating an FTPFile is a directory. ***/ + public static final int DIRECTORY_TYPE = 1; + /** A constant indicating an FTPFile is a symbolic link. ***/ + public static final int SYMBOLIC_LINK_TYPE = 2; + /** A constant indicating an FTPFile is of unknown type. ***/ + public static final int UNKNOWN_TYPE = 3; + + /** A constant indicating user access permissions. ***/ + public static final int USER_ACCESS = 0; + /** A constant indicating group access permissions. ***/ + public static final int GROUP_ACCESS = 1; + /** A constant indicating world access permissions. ***/ + public static final int WORLD_ACCESS = 2; + + /** A constant indicating file/directory read permission. ***/ + public static final int READ_PERMISSION = 0; + /** A constant indicating file/directory write permission. ***/ + public static final int WRITE_PERMISSION = 1; + /** + * A constant indicating file execute permission or directory listing + * permission. + ***/ + public static final int EXECUTE_PERMISSION = 2; + + int _type, _hardLinkCount; + long _size; + String _rawListing, _user, _group, _name, _link; + Calendar _date; + boolean[] _permissions[]; + + /*** Creates an empty FTPFile. ***/ + public FTPFile() + { + _permissions = new boolean[3][3]; + _rawListing = null; + _type = UNKNOWN_TYPE; + _hardLinkCount = 0; + _size = 0; + _user = null; + _group = null; + _date = null; + _name = null; + } + + + /*** + * Set the original FTP server raw listing from which the FTPFile was + * created. + *

+ * @param rawListing The raw FTP server listing. + ***/ + public void setRawListing(String rawListing) + { + _rawListing = rawListing; + } + + /*** + * Get the original FTP server raw listing used to initialize the FTPFile. + *

+ * @return The original FTP server raw listing used to initialize the + * FTPFile. + ***/ + public String getRawListing() + { + return _rawListing; + } + + + /*** + * Determine if the file is a directory. + *

+ * @return True if the file is of type DIRECTORY_TYPE, false if + * not. + ***/ + public boolean isDirectory() + { + return (_type == DIRECTORY_TYPE); + } + + /*** + * Determine if the file is a regular file. + *

+ * @return True if the file is of type FILE_TYPE, false if + * not. + ***/ + public boolean isFile() + { + return (_type == FILE_TYPE); + } + + /*** + * Determine if the file is a symbolic link. + *

+ * @return True if the file is of type UNKNOWN_TYPE, false if + * not. + ***/ + public boolean isSymbolicLink() + { + return (_type == SYMBOLIC_LINK_TYPE); + } + + /*** + * Determine if the type of the file is unknown. + *

+ * @return True if the file is of type UNKNOWN_TYPE, false if + * not. + ***/ + public boolean isUnknown() + { + return (_type == UNKNOWN_TYPE); + } + + + /*** + * Set the type of the file (DIRECTORY_TYPE, + * FILE_TYPE, etc.). + *

+ * @param type The integer code representing the type of the file. + ***/ + public void setType(int type) + { + _type = type; + } + + + /*** + * Return the type of the file (one of the _TYPE constants), + * e.g., if it is a directory, a regular file, or a symbolic link. + *

+ * @return The type of the file. + ***/ + public int getType() + { + return _type; + } + + + /*** + * Set the name of the file. + *

+ * @param name The name of the file. + ***/ + public void setName(String name) + { + _name = name; + } + + /*** + * Return the name of the file. + *

+ * @return The name of the file. + ***/ + public String getName() + { + return _name; + } + + + /** + * Set the file size in bytes. + * @param size The file size in bytes. + */ + public void setSize(long size) + { + _size = size; + } + + + /*** + * Return the file size in bytes. + *

+ * @return The file size in bytes. + ***/ + public long getSize() + { + return _size; + } + + + /*** + * Set the number of hard links to this file. This is not to be + * confused with symbolic links. + *

+ * @param links The number of hard links to this file. + ***/ + public void setHardLinkCount(int links) + { + _hardLinkCount = links; + } + + + /*** + * Return the number of hard links to this file. This is not to be + * confused with symbolic links. + *

+ * @return The number of hard links to this file. + ***/ + public int getHardLinkCount() + { + return _hardLinkCount; + } + + + /*** + * Set the name of the group owning the file. This may be + * a string representation of the group number. + *

+ * @param group The name of the group owning the file. + ***/ + public void setGroup(String group) + { + _group = group; + } + + + /*** + * Returns the name of the group owning the file. Sometimes this will be + * a string representation of the group number. + *

+ * @return The name of the group owning the file. + ***/ + public String getGroup() + { + return _group; + } + + + /*** + * Set the name of the user owning the file. This may be + * a string representation of the user number; + *

+ * @param user The name of the user owning the file. + ***/ + public void setUser(String user) + { + _user = user; + } + + /*** + * Returns the name of the user owning the file. Sometimes this will be + * a string representation of the user number. + *

+ * @return The name of the user owning the file. + ***/ + public String getUser() + { + return _user; + } + + + /*** + * If the FTPFile is a symbolic link, use this method to set the name of the + * file being pointed to by the symbolic link. + *

+ * @param link The file pointed to by the symbolic link. + ***/ + public void setLink(String link) + { + _link = link; + } + + + /*** + * If the FTPFile is a symbolic link, this method returns the name of the + * file being pointed to by the symbolic link. Otherwise it returns null. + *

+ * @return The file pointed to by the symbolic link (null if the FTPFile + * is not a symbolic link). + ***/ + public String getLink() + { + return _link; + } + + + /*** + * Set the file timestamp. This usually the last modification time. + * The parameter is not cloned, so do not alter its value after calling + * this method. + *

+ * @param date A Calendar instance representing the file timestamp. + ***/ + public void setTimestamp(Calendar date) + { + _date = date; + } + + + /*** + * Returns the file timestamp. This usually the last modification time. + *

+ * @return A Calendar instance representing the file timestamp. + ***/ + public Calendar getTimestamp() + { + return _date; + } + + + /*** + * Set if the given access group (one of the _ACCESS + * constants) has the given access permission (one of the + * _PERMISSION constants) to the file. + *

+ * @param access The access group (one of the _ACCESS + * constants) + * @param permission The access permission (one of the + * _PERMISSION constants) + * @param value True if permission is allowed, false if not. + ***/ + public void setPermission(int access, int permission, boolean value) + { + _permissions[access][permission] = value; + } + + + /*** + * Determines if the given access group (one of the _ACCESS + * constants) has the given access permission (one of the + * _PERMISSION constants) to the file. + *

+ * @param access The access group (one of the _ACCESS + * constants) + * @param permission The access permission (one of the + * _PERMISSION constants) + ***/ + public boolean hasPermission(int access, int permission) + { + return _permissions[access][permission]; + } + + + /*** + * Returns a string representation of the FTPFile information. This + * will be the raw FTP server listing that was used to initialize the + * FTPFile instance. + *

+ * @return A string representation of the FTPFile information. + ***/ + @Override + public String toString() + { + return _rawListing; + } + +} diff --git a/org/apache/commons/net/ftp/FTPFileEntryParser.class b/org/apache/commons/net/ftp/FTPFileEntryParser.class new file mode 100644 index 0000000..2643bb2 Binary files /dev/null and b/org/apache/commons/net/ftp/FTPFileEntryParser.class differ diff --git a/org/apache/commons/net/ftp/FTPFileEntryParser.java b/org/apache/commons/net/ftp/FTPFileEntryParser.java new file mode 100644 index 0000000..8e6d09c --- /dev/null +++ b/org/apache/commons/net/ftp/FTPFileEntryParser.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * FTPFileEntryParser defines the interface for parsing a single FTP file + * listing and converting that information into an + * {@link org.apache.commons.net.ftp.FTPFile} instance. + * Sometimes you will want to parse unusual listing formats, in which + * case you would create your own implementation of FTPFileEntryParser and + * if necessary, subclass FTPFile. + *

+ * Here are some examples showing how to use one of the classes that + * implement this interface. + *

+ * The first example shows how to get an iterable list of files in which the + * more expensive FTPFile objects are not created until needed. This + * is suitable for paged displays. It requires that a parser object be created + * beforehand: parser is an object (in the package + * org.apache.commons.net.ftp.parser) + * implementing this inteface. + * + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFileList list = f.createFileList(directory, parser);
+ *    FTPFileIterator iter = list.iterator();
+ *
+ *    while (iter.hasNext()) {
+ *       FTPFile[] files = iter.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ * + * The second example uses the revised FTPClient.listFiles() + * API to pull the whole list from the subfolder subfolder in + * one call, attempting to automatically detect the parser type. This + * method, without a parserKey parameter, indicates that autodection should + * be used. + * + *
+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = f.listFiles("subfolder");
+ * 
+ * + * The third example uses the revised FTPClient.listFiles()> + * API to pull the whole list from the current working directory in one call, + * but specifying by classname the parser to be used. For this particular + * parser class, this approach is necessary since there is no way to + * autodetect this server type. + * + *
+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = f.listFiles(
+ *      "org.apache.commons.net.ftp.parser.EnterpriseUnixFTPFileEntryParser",
+ *      ".");
+ * 
+ * + * The fourth example uses the revised FTPClient.listFiles() + * API to pull a single file listing in an arbitrary directory in one call, + * specifying by KEY the parser to be used, in this case, VMS. + * + *
+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = f.listFiles("VMS", "subfolder/foo.java");
+ * 
+ * + * @author Steve Cohen + * @version $Id: FTPFileEntryParser.java 636854 2008-03-13 19:55:01Z sebb $ + * @see org.apache.commons.net.ftp.FTPFile + * @see org.apache.commons.net.ftp.FTPClient#createFileList + */ +public interface FTPFileEntryParser +{ + /** + * Parses a line of an FTP server file listing and converts it into a usable + * format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null should be + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param listEntry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + FTPFile parseFTPEntry(String listEntry); + + /** + * Reads the next entry using the supplied BufferedReader object up to + * whatever delemits one entry from the next. Implementors must define + * this for the particular ftp system being parsed. In many but not all + * cases, this can be defined simply by calling BufferedReader.readLine(). + * + * @param reader The BufferedReader object from which entries are to be + * read. + * + * @return A string representing the next ftp entry or null if none found. + * @exception IOException thrown on any IO Error reading from the reader. + */ + String readNextEntry(BufferedReader reader) throws IOException; + + + /** + * This method is a hook for those implementors (such as + * VMSVersioningFTPEntryParser, and possibly others) which need to + * perform some action upon the FTPFileList after it has been created + * from the server stream, but before any clients see the list. + * + * The default implementation can be a no-op. + * + * @param original Original list after it has been created from the server stream + * + * @return Original list as processed by this method. + */ + List preParse(List original); + + +} + + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class b/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class new file mode 100644 index 0000000..aee0145 Binary files /dev/null and b/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class differ diff --git a/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java b/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java new file mode 100644 index 0000000..22214fe --- /dev/null +++ b/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +/** + * This abstract class implements both the older FTPFileListParser and + * newer FTPFileEntryParser interfaces with default functionality. + * All the classes in the parser subpackage inherit from this. + * + */ +public abstract class FTPFileEntryParserImpl + implements FTPFileEntryParser +{ + /** + * The constructor for a FTPFileEntryParserImpl object. + */ + public FTPFileEntryParserImpl() + { + } + + /** + * Reads the next entry using the supplied BufferedReader object up to + * whatever delemits one entry from the next. This default implementation + * simply calls BufferedReader.readLine(). + * + * @param reader The BufferedReader object from which entries are to be + * read. + * + * @return A string representing the next ftp entry or null if none found. + * @exception java.io.IOException thrown on any IO Error reading from the reader. + */ + public String readNextEntry(BufferedReader reader) throws IOException + { + return reader.readLine(); + } + /** + * This method is a hook for those implementors (such as + * VMSVersioningFTPEntryParser, and possibly others) which need to + * perform some action upon the FTPFileList after it has been created + * from the server stream, but before any clients see the list. + * + * This default implementation removes entries that do not parse as files. + * + * @param original Original list after it has been created from the server stream + * + * @return original unmodified. + */ + public List preParse(List original) { + Iterator it = original.iterator(); + while (it.hasNext()){ + String entry = it.next(); + if (null == parseFTPEntry(entry)) { + it.remove(); + } + } + return original; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/ftp/FTPListParseEngine.class b/org/apache/commons/net/ftp/FTPListParseEngine.class new file mode 100644 index 0000000..cc23486 Binary files /dev/null and b/org/apache/commons/net/ftp/FTPListParseEngine.class differ diff --git a/org/apache/commons/net/ftp/FTPListParseEngine.java b/org/apache/commons/net/ftp/FTPListParseEngine.java new file mode 100644 index 0000000..468bf39 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPListParseEngine.java @@ -0,0 +1,290 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + + +/** + * This class handles the entire process of parsing a listing of + * file entries from the server. + *

+ * This object defines a two-part parsing mechanism. + *

+ * The first part is comprised of reading the raw input into an internal + * list of strings. Every item in this list corresponds to an actual + * file. All extraneous matter emitted by the server will have been + * removed by the end of this phase. This is accomplished in conjunction + * with the FTPFileEntryParser associated with this engine, by calling + * its methods readNextEntry() - which handles the issue of + * what delimits one entry from another, usually but not always a line + * feed and preParse() - which handles removal of + * extraneous matter such as the preliminary lines of a listing, removal + * of duplicates on versioning systems, etc. + *

+ * The second part is composed of the actual parsing, again in conjunction + * with the particular parser used by this engine. This is controlled + * by an iterator over the internal list of strings. This may be done + * either in block mode, by calling the getNext() and + * getPrevious() methods to provide "paged" output of less + * than the whole list at one time, or by calling the + * getFiles() method to return the entire list. + *

+ * Examples: + *

+ * Paged access: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine = f.initiateListParsing(directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ * For unpaged access, simply use FTPClient.listFiles(). That method + * uses this class transparently. + * @version $Id: FTPListParseEngine.java 658518 2008-05-21 01:04:30Z sebb $ + */ +public class FTPListParseEngine { + private List entries = new LinkedList(); + private ListIterator _internalIterator = entries.listIterator(); + + FTPFileEntryParser parser = null; + + public FTPListParseEngine(FTPFileEntryParser parser) { + this.parser = parser; + } + + /** + * handle the iniitial reading and preparsing of the list returned by + * the server. After this method has completed, this object will contain + * a list of unparsed entries (Strings) each referring to a unique file + * on the server. + * + * @param stream input stream provided by the server socket. + * + * @exception IOException + * thrown on any failure to read from the sever. + */ + public void readServerList(InputStream stream, String encoding) + throws IOException + { + this.entries = new LinkedList(); + readStream(stream, encoding); + this.parser.preParse(this.entries); + resetIterator(); + } + + /** + * handle the iniitial reading and preparsing of the list returned by + * the server. After this method has completed, this object will contain + * a list of unparsed entries (Strings) each referring to a unique file + * on the server. + * + * @param stream input stream provided by the server socket. + * + * @exception IOException + * thrown on any failure to read from the sever. + * + * @deprecated The version of this method which takes an encoding should be used. + */ + public void readServerList(InputStream stream) + throws IOException + { + readServerList(stream, null); + } + + + + /** + * Internal method for reading the input into the entries list. + * After this method has completed, entries will contain a + * collection of entries (as defined by + * FTPFileEntryParser.readNextEntry()), but this may contain + * various non-entry preliminary lines from the server output, duplicates, + * and other data that will not be part of the final listing. + * + * @param stream The socket stream on which the input will be read. + * @param encoding The encoding to use. + * + * @exception IOException + * thrown on any failure to read the stream + */ + private void readStream(InputStream stream, String encoding) throws IOException + { + BufferedReader reader; + if (encoding == null) + { + reader = new BufferedReader(new InputStreamReader(stream)); + } + else + { + reader = new BufferedReader(new InputStreamReader(stream, encoding)); + } + + String line = this.parser.readNextEntry(reader); + + while (line != null) + { + this.entries.add(line); + line = this.parser.readNextEntry(reader); + } + reader.close(); + } + + /** + * Returns an array of at most quantityRequested FTPFile + * objects starting at this object's internal iterator's current position. + * If fewer than quantityRequested such + * elements are available, the returned array will have a length equal + * to the number of entries at and after after the current position. + * If no such entries are found, this array will have a length of 0. + * + * After this method is called this object's internal iterator is advanced + * by a number of positions equal to the size of the array returned. + * + * @param quantityRequested + * the maximum number of entries we want to get. + * + * @return an array of at most quantityRequested FTPFile + * objects starting at the current position of this iterator within its + * list and at least the number of elements which exist in the list at + * and after its current position. + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + */ + public FTPFile[] getNext(int quantityRequested) { + List tmpResults = new LinkedList(); + int count = quantityRequested; + while (count > 0 && this._internalIterator.hasNext()) { + String entry = this._internalIterator.next(); + FTPFile temp = this.parser.parseFTPEntry(entry); + tmpResults.add(temp); + count--; + } + return tmpResults.toArray(new FTPFile[0]); + + } + + /** + * Returns an array of at most quantityRequested FTPFile + * objects starting at this object's internal iterator's current position, + * and working back toward the beginning. + * + * If fewer than quantityRequested such + * elements are available, the returned array will have a length equal + * to the number of entries at and after after the current position. + * If no such entries are found, this array will have a length of 0. + * + * After this method is called this object's internal iterator is moved + * back by a number of positions equal to the size of the array returned. + * + * @param quantityRequested + * the maximum number of entries we want to get. + * + * @return an array of at most quantityRequested FTPFile + * objects starting at the current position of this iterator within its + * list and at least the number of elements which exist in the list at + * and after its current position. This array will be in the same order + * as the underlying list (not reversed). + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + */ + public FTPFile[] getPrevious(int quantityRequested) { + List tmpResults = new LinkedList(); + int count = quantityRequested; + while (count > 0 && this._internalIterator.hasPrevious()) { + String entry = this._internalIterator.previous(); + FTPFile temp = this.parser.parseFTPEntry(entry); + tmpResults.add(0,temp); + count--; + } + return tmpResults.toArray(new FTPFile[0]); + } + + /** + * Returns an array of FTPFile objects containing the whole list of + * files returned by the server as read by this object's parser. + * + * @return an array of FTPFile objects containing the whole list of + * files returned by the server as read by this object's parser. + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + * @exception IOException + */ + public FTPFile[] getFiles() + throws IOException + { + List tmpResults = new LinkedList(); + Iterator iter = this.entries.iterator(); + while (iter.hasNext()) { + String entry = iter.next(); + FTPFile temp = this.parser.parseFTPEntry(entry); + tmpResults.add(temp); + } + return tmpResults.toArray(new FTPFile[0]); + + } + + /** + * convenience method to allow clients to know whether this object's + * internal iterator's current position is at the end of the list. + * + * @return true if internal iterator is not at end of list, false + * otherwise. + */ + public boolean hasNext() { + return _internalIterator.hasNext(); + } + + /** + * convenience method to allow clients to know whether this object's + * internal iterator's current position is at the beginning of the list. + * + * @return true if internal iterator is not at beginning of list, false + * otherwise. + */ + public boolean hasPrevious() { + return _internalIterator.hasPrevious(); + } + + /** + * resets this object's internal iterator to the beginning of the list. + */ + public void resetIterator() { + this._internalIterator = this.entries.listIterator(); + } +} diff --git a/org/apache/commons/net/ftp/FTPReply.class b/org/apache/commons/net/ftp/FTPReply.class new file mode 100644 index 0000000..2d596ba Binary files /dev/null and b/org/apache/commons/net/ftp/FTPReply.class differ diff --git a/org/apache/commons/net/ftp/FTPReply.java b/org/apache/commons/net/ftp/FTPReply.java new file mode 100644 index 0000000..6386568 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPReply.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +/*** + * FTPReply stores a set of constants for FTP reply codes. To interpret + * the meaning of the codes, familiarity with RFC 959 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 959. For those who think in terms of the actual reply code values, + * a set of CODE_NUM constants are provided where NUM is the numerical value + * of the code. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FTPReply +{ + + public static final int CODE_110 = 110; + public static final int CODE_120 = 120; + public static final int CODE_125 = 125; + public static final int CODE_150 = 150; + public static final int CODE_200 = 200; + public static final int CODE_202 = 202; + public static final int CODE_211 = 211; + public static final int CODE_212 = 212; + public static final int CODE_213 = 213; + public static final int CODE_214 = 214; + public static final int CODE_215 = 215; + public static final int CODE_220 = 220; + public static final int CODE_221 = 221; + public static final int CODE_225 = 225; + public static final int CODE_226 = 226; + public static final int CODE_227 = 227; + public static final int CODE_230 = 230; + public static final int CODE_250 = 250; + public static final int CODE_257 = 257; + public static final int CODE_331 = 331; + public static final int CODE_332 = 332; + public static final int CODE_350 = 350; + public static final int CODE_421 = 421; + public static final int CODE_425 = 425; + public static final int CODE_426 = 426; + public static final int CODE_450 = 450; + public static final int CODE_451 = 451; + public static final int CODE_452 = 452; + public static final int CODE_500 = 500; + public static final int CODE_501 = 501; + public static final int CODE_502 = 502; + public static final int CODE_503 = 503; + public static final int CODE_504 = 504; + public static final int CODE_521 = 521; + public static final int CODE_530 = 530; + public static final int CODE_532 = 532; + public static final int CODE_550 = 550; + public static final int CODE_551 = 551; + public static final int CODE_552 = 552; + public static final int CODE_553 = 553; + + public static final int RESTART_MARKER = CODE_110; + public static final int SERVICE_NOT_READY = CODE_120; + public static final int DATA_CONNECTION_ALREADY_OPEN = CODE_125; + public static final int FILE_STATUS_OK = CODE_150; + public static final int COMMAND_OK = CODE_200; + public static final int COMMAND_IS_SUPERFLUOUS = CODE_202; + public static final int SYSTEM_STATUS = CODE_211; + public static final int DIRECTORY_STATUS = CODE_212; + public static final int FILE_STATUS = CODE_213; + public static final int HELP_MESSAGE = CODE_214; + public static final int NAME_SYSTEM_TYPE = CODE_215; + public static final int SERVICE_READY = CODE_220; + public static final int SERVICE_CLOSING_CONTROL_CONNECTION = CODE_221; + public static final int DATA_CONNECTION_OPEN = CODE_225; + public static final int CLOSING_DATA_CONNECTION = CODE_226; + public static final int ENTERING_PASSIVE_MODE = CODE_227; + public static final int USER_LOGGED_IN = CODE_230; + public static final int FILE_ACTION_OK = CODE_250; + public static final int PATHNAME_CREATED = CODE_257; + public static final int NEED_PASSWORD = CODE_331; + public static final int NEED_ACCOUNT = CODE_332; + public static final int FILE_ACTION_PENDING = CODE_350; + public static final int SERVICE_NOT_AVAILABLE = CODE_421; + public static final int CANNOT_OPEN_DATA_CONNECTION = CODE_425; + public static final int TRANSFER_ABORTED = CODE_426; + public static final int FILE_ACTION_NOT_TAKEN = CODE_450; + public static final int ACTION_ABORTED = CODE_451; + public static final int INSUFFICIENT_STORAGE = CODE_452; + public static final int UNRECOGNIZED_COMMAND = CODE_500; + public static final int SYNTAX_ERROR_IN_ARGUMENTS = CODE_501; + public static final int COMMAND_NOT_IMPLEMENTED = CODE_502; + public static final int BAD_COMMAND_SEQUENCE = CODE_503; + public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = CODE_504; + public static final int NOT_LOGGED_IN = CODE_530; + public static final int NEED_ACCOUNT_FOR_STORING_FILES = CODE_532; + public static final int FILE_UNAVAILABLE = CODE_550; + public static final int PAGE_TYPE_UNKNOWN = CODE_551; + public static final int STORAGE_ALLOCATION_EXCEEDED = CODE_552; + public static final int FILE_NAME_NOT_ALLOWED = CODE_553; + + // FTPS Reply Codes + /** @since 2.0 */ + public static final int CODE_234 = 234; + /** @since 2.0 */ + public static final int CODE_235 = 235; + /** @since 2.0 */ + public static final int CODE_334 = 334; + /** @since 2.0 */ + public static final int CODE_335 = 335; + /** @since 2.0 */ + public static final int CODE_431 = 431; + /** @since 2.0 */ + public static final int CODE_533 = 533; + /** @since 2.0 */ + public static final int CODE_534 = 534; + /** @since 2.0 */ + public static final int CODE_535 = 535; + /** @since 2.0 */ + public static final int CODE_536 = 536; + + /** @since 2.0 */ + public static final int SECURITY_DATA_EXCHANGE_COMPLETE = CODE_234; + /** @since 2.0 */ + public static final int SECURITY_DATA_EXCHANGE_SUCCESSFULLY = CODE_235; + /** @since 2.0 */ + public static final int SECURITY_MECHANISM_IS_OK = CODE_334; + /** @since 2.0 */ + public static final int SECURITY_DATA_IS_ACCEPTABLE = CODE_335; + /** @since 2.0 */ + public static final int UNAVAILABLE_RESOURCE = CODE_431; + /** @since 2.0 */ + public static final int DENIED_FOR_POLICY_REASONS = CODE_533; + /** @since 2.0 */ + public static final int REQUEST_DENIED = CODE_534; + /** @since 2.0 */ + public static final int FAILED_SECURITY_CHECK = CODE_535; + /** @since 2.0 */ + public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = CODE_536; + + + // Cannot be instantiated + private FTPReply() + {} + + /*** + * Determine if a reply code is a positive preliminary response. All + * codes beginning with a 1 are positive preliminary responses. + * Postitive preliminary responses are used to indicate tentative success. + * No further commands can be issued to the FTP server after a positive + * preliminary response until a follow up response is received from the + * server. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive preliminary response, false + * if not. + ***/ + public static boolean isPositivePreliminary(int reply) + { + return (reply >= 100 && reply < 200); + } + + /*** + * Determine if a reply code is a positive completion response. All + * codes beginning with a 2 are positive completion responses. + * The FTP server will send a positive completion response on the final + * successful completion of a command. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive completion response, false + * if not. + ***/ + public static boolean isPositiveCompletion(int reply) + { + return (reply >= 200 && reply < 300); + } + + /*** + * Determine if a reply code is a positive intermediate response. All + * codes beginning with a 3 are positive intermediate responses. + * The FTP server will send a positive intermediate response on the + * successful completion of one part of a multi-part sequence of + * commands. For example, after a successful USER command, a positive + * intermediate response will be sent to indicate that the server is + * ready for the PASS command. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive intermediate response, false + * if not. + ***/ + public static boolean isPositiveIntermediate(int reply) + { + return (reply >= 300 && reply < 400); + } + + /*** + * Determine if a reply code is a negative transient response. All + * codes beginning with a 4 are negative transient responses. + * The FTP server will send a negative transient response on the + * failure of a command that can be reattempted with success. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative transient response, false + * if not. + ***/ + public static boolean isNegativeTransient(int reply) + { + return (reply >= 400 && reply < 500); + } + + /*** + * Determine if a reply code is a negative permanent response. All + * codes beginning with a 5 are negative permanent responses. + * The FTP server will send a negative permanent response on the + * failure of a command that cannot be reattempted with success. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative permanent response, false + * if not. + ***/ + public static boolean isNegativePermanent(int reply) + { + return (reply >= 500 && reply < 600); + } + +} diff --git a/org/apache/commons/net/ftp/FTPSClient.java b/org/apache/commons/net/ftp/FTPSClient.java new file mode 100644 index 0000000..f809c41 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPSClient.java @@ -0,0 +1,533 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +/** + * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to + * see wire-level SSL details. + * + * @version $Id: FTPSClient.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 2.0 + */ +public class FTPSClient extends FTPClient { + + /** keystore algorithm name. */ + public static String KEYSTORE_ALGORITHM; + /** truststore algorithm name. */ + public static String TRUSTSTORE_ALGORITHM; + /** provider name. */ + public static String PROVIDER; + /** truststore type. */ + public static String STORE_TYPE; + + /** The value that I can set in PROT command */ + private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; + /** Default PROT Command */ + private static final String DEFAULT_PROT = "C"; + /** Default protocol name */ + private static final String DEFAULT_PROTOCOL = "TLS"; + + /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ + private boolean isImplicit; + /** The use SSL/TLS protocol. */ + private String protocol = DEFAULT_PROTOCOL; + /** The AUTH Command value */ + private String auth = DEFAULT_PROTOCOL; + /** The context object. */ + private SSLContext context; + /** The socket object. */ + private Socket planeSocket; + /** The established socket flag. */ + private boolean isCreation = true; + /** The use client mode flag. */ + private boolean isClientMode = true; + /** The need client auth flag. */ + private boolean isNeedClientAuth = false; + /** The want client auth flag. */ + private boolean isWantClientAuth = false; + /** The cipher suites */ + private String[] suites = null; + /** The protocol versions */ + private String[] protocols = null; + + /** The FTPS {@link TrustManager} implementation. */ + private TrustManager trustManager = new FTPSTrustManager(); + + /** The {@link KeyManager} */ + private KeyManager keyManager; + + /** + * Constructor for FTPSClient. + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient() throws NoSuchAlgorithmException { + this.protocol = DEFAULT_PROTOCOL; + this.isImplicit = false; + } + + /** + * Constructor for FTPSClient. + * @param isImplicit The secutiry mode(Implicit/Explicit). + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient(boolean isImplicit) throws NoSuchAlgorithmException { + this.protocol = DEFAULT_PROTOCOL; + this.isImplicit = isImplicit; + } + + /** + * Constructor for FTPSClient. + * @param protocol the protocol + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient(String protocol) throws NoSuchAlgorithmException { + this.protocol = protocol; + this.isImplicit = false; + } + + /** + * Constructor for FTPSClient. + * @param protocol the protocol + * @param isImplicit The secutiry mode(Implicit/Explicit). + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient(String protocol, boolean isImplicit) + throws NoSuchAlgorithmException { + this.protocol = protocol; + this.isImplicit = isImplicit; + } + + + /** + * Set AUTH command use value. + * This processing is done before connected processing. + * @param auth AUTH command use value. + */ + public void setAuthValue(String auth) { + this.auth = auth; + } + + /** + * Return AUTH command use value. + * @return AUTH command use value. + */ + public String getAuthValue() { + return this.auth; + } + + + /** + * Because there are so many connect() methods, + * the _connectAction_() method is provided as a means of performing + * some action immediately after establishing a connection, + * rather than reimplementing all of the connect() methods. + * @throws IOException If it throw by _connectAction_. + * @see org.apache.commons.net.SocketClient#_connectAction_() + */ + @Override + protected void _connectAction_() throws IOException { + // Implicit mode. + if (isImplicit) sslNegotiation(); + super._connectAction_(); + // Explicit mode. + if (!isImplicit) { + execAUTH(); + sslNegotiation(); + } + } + + /** + * AUTH command. + * @throws SSLException If it server reply code not equal "234" and "334". + * @throws IOException If an I/O error occurs while either sending + * the command. + */ + private void execAUTH() throws SSLException, IOException { + int replyCode = sendCommand( + FTPSCommand._commands[FTPSCommand.AUTH], auth); + if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { + // replyCode = 334 + // I carry out an ADAT command. + } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { + throw new SSLException(getReplyString()); + } + } + + /** + * Performs a lazy init of the SSL context + * @throws IOException + */ + private void initSslContext() throws IOException { + if(context == null) { + try { + context = SSLContext.getInstance(protocol); + + context.init(new KeyManager[] { getKeyManager() } , new TrustManager[] { getTrustManager() } , null); + } catch (KeyManagementException e) { + IOException ioe = new IOException("Could not initialize SSL context"); + ioe.initCause(e); + throw ioe; + } catch (NoSuchAlgorithmException e) { + IOException ioe = new IOException("Could not initialize SSL context"); + ioe.initCause(e); + throw ioe; + } + } + } + + /** + * SSL/TLS negotiation. Acquires an SSL socket of a control + * connection and carries out handshake processing. + * @throws IOException A handicap breaks out by sever negotiation. + */ + private void sslNegotiation() throws IOException { + // Evacuation not ssl socket. + planeSocket = _socket_; + + initSslContext(); + + SSLSocketFactory ssf = context.getSocketFactory(); + String ip = _socket_.getInetAddress().getHostAddress(); + int port = _socket_.getPort(); + SSLSocket socket = + (SSLSocket) ssf.createSocket(_socket_, ip, port, true); + socket.setEnableSessionCreation(isCreation); + socket.setUseClientMode(isClientMode); + // server mode + if (!isClientMode) { + socket.setNeedClientAuth(isNeedClientAuth); + socket.setWantClientAuth(isWantClientAuth); + } + if (protocols != null) socket.setEnabledProtocols(protocols); + if (suites != null) socket.setEnabledCipherSuites(suites); + + socket.startHandshake(); + + _socket_ = socket; + _controlInput_ = new BufferedReader(new InputStreamReader( + socket .getInputStream(), getControlEncoding())); + _controlOutput_ = new BufferedWriter(new OutputStreamWriter( + socket.getOutputStream(), getControlEncoding())); + } + + /** + * Get the {@link KeyManager} instance. + * @return The {@link KeyManager} instance + */ + private KeyManager getKeyManager() { + return keyManager; + } + + /** + * Set a {@link KeyManager} to use + * + * @param keyManager The KeyManager implementation to set. + */ + public void setKeyManager(KeyManager keyManager) { + this.keyManager = keyManager; + } + + /** + * Controls whether new a SSL session may be established by this socket. + * @param isCreation The established socket flag. + */ + public void setEnabledSessionCreation(boolean isCreation) { + this.isCreation = isCreation; + } + + /** + * Returns true if new SSL sessions may be established by this socket. + * When a socket does not have a ssl socket, This return False. + * @return true - Indicates that sessions may be created; + * this is the default. + * false - indicates that an existing session must be resumed. + */ + public boolean getEnableSessionCreation() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getEnableSessionCreation(); + return false; + } + + /** + * Configures the socket to require client authentication. + * @param isNeedClientAuth The need client auth flag. + */ + public void setNeedClientAuth(boolean isNeedClientAuth) { + this.isNeedClientAuth = isNeedClientAuth; + } + + /** + * Returns true if the socket will require client authentication. + * When a socket does not have a ssl socket, This return False. + * @return true - If the server mode socket should request + * that the client authenticate itself. + */ + public boolean getNeedClientAuth() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getNeedClientAuth(); + return false; + } + + /** + * Configures the socket to request client authentication, + * but only if such a request is appropriate to the cipher + * suite negotiated. + * @param isWantClientAuth The want client auth flag. + */ + public void setWantClientAuth(boolean isWantClientAuth) { + this.isWantClientAuth = isWantClientAuth; + } + + /** + * Returns true if the socket will request client authentication. + * When a socket does not have a ssl socket, This return False. + * @return true - If the server mode socket should request + * that the client authenticate itself. + */ + public boolean getWantClientAuth() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getWantClientAuth(); + return false; + } + + /** + * Configures the socket to use client (or server) mode in its first + * handshake. + * @param isClientMode The use client mode flag. + */ + public void setUseClientMode(boolean isClientMode) { + this.isClientMode = isClientMode; + } + + /** + * Returns true if the socket is set to use client mode + * in its first handshake. + * When a socket does not have a ssl socket, This return False. + * @return true - If the socket should start its first handshake + * in "client" mode. + */ + public boolean getUseClientMode() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getUseClientMode(); + return false; + } + + /** + * Controls which particular cipher suites are enabled for use on this + * connection. I perform setting before a server negotiation. + * @param cipherSuites The cipher suites. + */ + public void setEnabledCipherSuites(String[] cipherSuites) { + suites = new String[cipherSuites.length]; + System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); + } + + /** + * Returns the names of the cipher suites which could be enabled + * for use on this connection. + * When a socket does not have a ssl socket, This return null. + * @return An array of cipher suite names. + */ + public String[] getEnabledCipherSuites() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getEnabledCipherSuites(); + return null; + } + + /** + * Controls which particular protocol versions are enabled for use on this + * connection. I perform setting before a server negotiation. + * @param protocolVersions The protocol versions. + */ + public void setEnabledProtocols(String[] protocolVersions) { + protocols = new String[protocolVersions.length]; + System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); + } + + /** + * Returns the names of the protocol versions which are currently + * enabled for use on this connection. + * When a socket does not have a ssl socket, This return null. + * @return An array of protocols. + */ + public String[] getEnabledProtocols() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getEnabledProtocols(); + return null; + } + + /** + * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. + * @param pbsz Protection Buffer Size. + * @throws SSLException If it server reply code not equal "200". + * @throws IOException If an I/O error occurs while either sending + * the command. + */ + public void execPBSZ(long pbsz) throws SSLException, IOException { + if (pbsz < 0 || 4294967295L < pbsz) + throw new IllegalArgumentException(); + if (FTPReply.COMMAND_OK != sendCommand( + FTPSCommand._commands[FTPSCommand.PBSZ],String.valueOf(pbsz))) + throw new SSLException(getReplyString()); + } + + /** + * PROT command.
+ * C - Clear
+ * S - Safe(SSL protocol only)
+ * E - Confidential(SSL protocol only)
+ * P - Private + * @param prot Data Channel Protection Level. + * @throws SSLException If it server reply code not equal "200". + * @throws IOException If an I/O error occurs while either sending + * the command. + */ + public void execPROT(String prot) throws SSLException, IOException { + if (prot == null) prot = DEFAULT_PROT; + if (!checkPROTValue(prot)) throw new IllegalArgumentException(); + if (FTPReply.COMMAND_OK != sendCommand( + FTPSCommand._commands[FTPSCommand.PROT], prot)) + throw new SSLException(getReplyString()); + if (DEFAULT_PROT.equals(prot)) { + setSocketFactory(null); + setServerSocketFactory(null); + } else { + setSocketFactory(new FTPSSocketFactory(context)); + + initSslContext(); + + SSLServerSocketFactory ssf = context.getServerSocketFactory(); + + setServerSocketFactory(ssf); + } + } + + /** + * I check the value that I can set in PROT Command value. + * @param prot Data Channel Protection Level. + * @return True - A set point is right / False - A set point is not right + */ + private boolean checkPROTValue(String prot) { + for (int p = 0; p < PROT_COMMAND_VALUE.length; p++) { + if (PROT_COMMAND_VALUE[p].equals(prot)) return true; + } + return false; + } + + /** + * I carry out an ftp command. + * When a CCC command was carried out, I steep socket and SocketFactory + * in a state of not ssl. + * @parm command ftp command. + * @return server reply. + * @throws IOException If an I/O error occurs while either sending + * the command. + * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) + */ + @Override + public int sendCommand(String command, String args) throws IOException { + int repCode = super.sendCommand(command, args); + if (FTPSCommand._commands[FTPSCommand.CCC].equals(command)) { + if (FTPReply.COMMAND_OK == repCode) { + // TODO Check this - is this necessary at all? + _socket_ = planeSocket; + setSocketFactory(null); + } else { + throw new SSLException(getReplyString()); + } + } + return repCode; + } + + /** + * Returns a socket of the data connection. + * Wrapped as an {@link SSLSocket}, which carries out handshake processing. + * @pram command The text representation of the FTP command to send. + * @param arg The arguments to the FTP command. + * If this parameter is set to null, then the command is sent with + * no argument. + * @return A Socket corresponding to the established data connection. + * Null is returned if an FTP protocol error is reported at any point + * during the establishment and initialization of the connection. + * @throws IOException If there is any problem with the connection. + * @see org.apache.commons.net.ftp.FTPClient#_openDataConnection_(java.lang.String, int) + */ + @Override + protected Socket _openDataConnection_(int command, String arg) + throws IOException { + Socket socket = super._openDataConnection_(command, arg); + if (socket != null && socket instanceof SSLSocket) { + SSLSocket sslSocket = (SSLSocket)socket; + sslSocket.setUseClientMode(isClientMode); + sslSocket.setEnableSessionCreation(isCreation); + // server mode + if (!isClientMode) { + sslSocket.setNeedClientAuth(isNeedClientAuth); + sslSocket.setWantClientAuth(isWantClientAuth); + } + if (suites != null) + sslSocket.setEnabledCipherSuites(suites); + if (protocols != null) + sslSocket.setEnabledProtocols(protocols); + sslSocket.startHandshake(); + } + return socket; + } + + /** + * Get the currently configured {@link TrustManager}. + * + * @return A TrustManager instance. + */ + public TrustManager getTrustManager() { + return trustManager; + } + + /** + * Override the default {@link TrustManager} to use. + * + * @param trustManager The TrustManager implementation to set. + */ + public void setTrustManager(TrustManager trustManager) { + this.trustManager = trustManager; + } + + + +} diff --git a/org/apache/commons/net/ftp/FTPSCommand.java b/org/apache/commons/net/ftp/FTPSCommand.java new file mode 100644 index 0000000..6fd2efa --- /dev/null +++ b/org/apache/commons/net/ftp/FTPSCommand.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +/** + * I acquire a command added in FTPS. + * @since 2.0 + */ +public final class FTPSCommand { + public static final int AUTH = 0; + public static final int ADAT = 1; + public static final int PBSZ = 2; + public static final int PROT = 3; + public static final int CCC = 4; + + public static final int AUTHENTICATION_SECURITY_MECHANISM = AUTH; + public static final int AUTHENTICATION_SECURITY_DATA = ADAT; + public static final int PROTECTION_BUFFER_SIZE = PBSZ; + public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; + public static final int CLEAR_COMMAND_CHANNEL = CCC; + + static final String[] _commands = {"AUTH","ADAT","PBSZ","PROT","CCC"}; + + /** + * Retrieve the FTPS command string corresponding to a specified + * command code. + *

+ * @param command The command code. + * @return The FTPS command string corresponding to a specified + * command code. + */ + public static final String getCommand(int command) { + return _commands[command]; + } +} diff --git a/org/apache/commons/net/ftp/FTPSSocketFactory.java b/org/apache/commons/net/ftp/FTPSSocketFactory.java new file mode 100644 index 0000000..b7e1186 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPSSocketFactory.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.net.ftp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; + + +/** + * + * Implementation of org.apache.commons.net.SocketFactory + * + * @since 2.0 + */ +public class FTPSSocketFactory extends SocketFactory { + + private SSLContext context; + + public FTPSSocketFactory(SSLContext context) { + this.context = context; + } + + @Override + public Socket createSocket(String address, int port) throws UnknownHostException, IOException { + return this.context.getSocketFactory().createSocket(address, port); + } + + @Override + public Socket createSocket(InetAddress address, int port) throws IOException { + return this.context.getSocketFactory().createSocket(address, port); + } + + @Override + public Socket createSocket(String address, int port, InetAddress localAddress, int localPort) throws UnknownHostException, IOException { + return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); + } + + public ServerSocket createServerSocket(int port) throws IOException { + return this.init(this.context.getServerSocketFactory().createServerSocket(port)); + } + + public ServerSocket createServerSocket(int port, int backlog) throws IOException { + return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); + } + + public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { + return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); + } + + public ServerSocket init(ServerSocket socket) throws IOException { + ((SSLServerSocket) socket).setUseClientMode(true); + return socket; + } +} diff --git a/org/apache/commons/net/ftp/FTPSTrustManager.java b/org/apache/commons/net/ftp/FTPSTrustManager.java new file mode 100644 index 0000000..d1a2dd7 --- /dev/null +++ b/org/apache/commons/net/ftp/FTPSTrustManager.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * Custom {@link TrustManager} implementation. + * + * @version $Id: FTPSTrustManager.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 2.0 + */ +public class FTPSTrustManager implements X509TrustManager +{ + /** + * No-op + */ + public void checkClientTrusted(X509Certificate[] certificates, String authType) + { + return; + } + + public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException + { + for (int i = 0; i < certificates.length; ++i) + { + certificates[i].checkValidity(); + } + } + + public X509Certificate[] getAcceptedIssuers() + { + return null; + } +} diff --git a/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class b/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class new file mode 100644 index 0000000..0beda53 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java b/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java new file mode 100644 index 0000000..4977b3f --- /dev/null +++ b/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPFileEntryParser; +import org.apache.commons.net.ftp.FTPFileEntryParserImpl; + +/** + * This implementation allows to pack some FileEntryParsers together + * and handle the case where to returned dirstyle isnt clearly defined. + * The matching parser will be cached. + * If the cached parser wont match due to the server changed the dirstyle, + * a new matching parser will be searched. + * + * @author Mario Ivankovits + */ +public class CompositeFileEntryParser extends FTPFileEntryParserImpl +{ + private final FTPFileEntryParser[] ftpFileEntryParsers; + private FTPFileEntryParser cachedFtpFileEntryParser; + + public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) + { + super(); + + this.cachedFtpFileEntryParser = null; + this.ftpFileEntryParsers = ftpFileEntryParsers; + } + + public FTPFile parseFTPEntry(String listEntry) + { + if (cachedFtpFileEntryParser != null) + { + FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); + if (matched != null) + { + return matched; + } + } + else + { + for (int iterParser=0; iterParser < ftpFileEntryParsers.length; iterParser++) + { + FTPFileEntryParser ftpFileEntryParser = ftpFileEntryParsers[iterParser]; + + FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); + if (matched != null) + { + cachedFtpFileEntryParser = ftpFileEntryParser; + return matched; + } + } + } + return null; + } +} diff --git a/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class b/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class new file mode 100644 index 0000000..5cbb5d5 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class differ diff --git a/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java b/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java new file mode 100644 index 0000000..a3e832f --- /dev/null +++ b/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; +import java.util.Calendar; + +import org.apache.commons.net.ftp.Configurable; +import org.apache.commons.net.ftp.FTPClientConfig; + + +/** + *

+ * This abstract class implements the common timestamp parsing + * algorithm for all the concrete parsers. Classes derived from + * this one will parse file listings via a supplied regular expression + * that pulls out the date portion as a separate string which is + * passed to the underlying {@link FTPTimestampParser delegate} to + * handle parsing of the file timestamp. + *

+ * This class also implements the {@link Configurable Configurable} + * interface to allow the parser to be configured from the outside. + *

+ * @since 1.4 + */ +/** + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Style - Code Templates - Comments + */ +public abstract class ConfigurableFTPFileEntryParserImpl +extends RegexFTPFileEntryParserImpl +implements Configurable +{ + + private FTPTimestampParser timestampParser; + + /** + * Only constructor for this absract class. + * @param regex Regular expression used main parsing of the + * file listing. + */ + public ConfigurableFTPFileEntryParserImpl(String regex) + { + super(regex); + this.timestampParser = new FTPTimestampParserImpl(); + } + + /** + * This method is called by the concrete parsers to delegate + * timestamp parsing to the timestamp parser. + *

+ * @param timestampStr the timestamp string pulled from the + * file listing by the regular expression parser, to be submitted + * to the timestampParser for extracting the timestamp. + * @return a java.util.Calendar containing results of the + * timestamp parse. + */ + public Calendar parseTimestamp(String timestampStr) throws ParseException { + return this.timestampParser.parseTimestamp(timestampStr); + } + + + /** + * Implementation of the {@link Configurable Configurable} + * interface. Configures this parser by delegating to the + * underlying Configurable FTPTimestampParser implementation, ' + * passing it the supplied {@link FTPClientConfig FTPClientConfig} + * if that is non-null or a default configuration defined by + * each concrete subclass. + *

+ * @param config the configuration to be used to configure this parser. + * If it is null, a default configuration defined by + * each concrete subclass is used instead. + */ + public void configure(FTPClientConfig config) + { + if (this.timestampParser instanceof Configurable) { + FTPClientConfig defaultCfg = getDefaultConfiguration(); + if (config != null) { + if (null == config.getDefaultDateFormatStr()) { + config.setDefaultDateFormatStr(defaultCfg.getDefaultDateFormatStr()); + } + if (null == config.getRecentDateFormatStr()) { + config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); + } + ((Configurable)this.timestampParser).configure(config); + } else { + ((Configurable)this.timestampParser).configure(defaultCfg); + } + } + } + + /** + * Each concrete subclass must define this member to create + * a default configuration to be used when that subclass is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for the subclass. + */ + protected abstract FTPClientConfig getDefaultConfiguration(); +} diff --git a/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class b/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class new file mode 100644 index 0000000..a4da6ed Binary files /dev/null and b/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class differ diff --git a/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java b/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java new file mode 100644 index 0000000..c071a8e --- /dev/null +++ b/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import org.apache.commons.net.ftp.Configurable; +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFileEntryParser; + + +/** + * This is the default implementation of the + * FTPFileEntryParserFactory interface. This is the + * implementation that will be used by + * org.apache.commons.net.ftp.FTPClient.listFiles() + * if no other implementation has been specified. + * + * @see org.apache.commons.net.ftp.FTPClient#listFiles + * @see org.apache.commons.net.ftp.FTPClient#setParserFactory + */ +public class DefaultFTPFileEntryParserFactory + implements FTPFileEntryParserFactory +{ + private FTPClientConfig config = null; + + /** + * This default implementation of the FTPFileEntryParserFactory + * interface works according to the following logic: + * First it attempts to interpret the supplied key as a fully + * qualified classname of a class implementing the + * FTPFileEntryParser interface. If that succeeds, a parser + * object of this class is instantiated and is returned; + * otherwise it attempts to interpret the key as an identirier + * commonly used by the FTP SYST command to identify systems. + *

+ * If key is not recognized as a fully qualified + * classname known to the system, this method will then attempt + * to see whether it contains a string identifying one of + * the known parsers. This comparison is case-insensitive. + * The intent here is where possible, to select as keys strings + * which are returned by the SYST command on the systems which + * the corresponding parser successfully parses. This enables + * this factory to be used in the auto-detection system. + *

+ * + * @param key should be a fully qualified classname corresponding to + * a class implementing the FTPFileEntryParser interface
+ * OR
+ * a string containing (case-insensitively) one of the + * following keywords: + *

    + *
  • {@link FTPClientConfig#SYST_UNIX UNIX}
  • + *
  • {@link FTPClientConfig#SYST_NT WINDOWS}
  • + *
  • {@link FTPClientConfig#SYST_OS2 OS/2}
  • + *
  • {@link FTPClientConfig#SYST_OS400 OS/400}
  • + *
  • {@link FTPClientConfig#SYST_VMS VMS}
  • + *
  • {@link FTPClientConfig#SYST_MVS MVS}
  • + *
  • {@link FTPClientConfig#SYST_NETWARE}
  • + *
+ * @return the FTPFileEntryParser corresponding to the supplied key. + * @throws ParserInitializationException thrown if for any reason the factory cannot resolve + * the supplied key into an FTPFileEntryParser. + * @see FTPFileEntryParser + */ + public FTPFileEntryParser createFileEntryParser(String key) + { + if (key == null) + throw new ParserInitializationException("Parser key cannot be null"); + + Class parserClass = null; + FTPFileEntryParser parser = null; + try + { + parserClass = Class.forName(key); + parser = (FTPFileEntryParser) parserClass.newInstance(); + } + catch (ClassNotFoundException e) + { + try + { + String ukey = null; + if (null != key) + { + ukey = key.toUpperCase(java.util.Locale.ENGLISH); + } + if ((ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) + || (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0)) + { + parser = createUnixFTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) + { + parser = createVMSVersioningFTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) + { + parser = createNTFTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) + { + parser = createOS2FTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 || + ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) + { + parser = createOS400FTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) + { + parser = createMVSEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) + { + parser = createNetwareFTPEntryParser(); + } + else + { + throw new ParserInitializationException("Unknown parser type: " + key); + } + } + catch (NoClassDefFoundError nf) { + throw new ParserInitializationException("Error initializing parser", nf); + } + + } + catch (NoClassDefFoundError e) + { + throw new ParserInitializationException("Error initializing parser", e); + } + catch (ClassCastException e) + { + throw new ParserInitializationException(parserClass.getName() + + " does not implement the interface " + + "org.apache.commons.net.ftp.FTPFileEntryParser.", e); + } + catch (Throwable e) + { + throw new ParserInitializationException("Error initializing parser", e); + } + + if (parser instanceof Configurable) { + ((Configurable)parser).configure(this.config); + } + return parser; + } + + /** + *

Implementation extracts a key from the supplied + * {@link FTPClientConfig FTPClientConfig} + * parameter and creates an object implementing the + * interface FTPFileEntryParser and uses the supplied configuration + * to configure it. + *

+ * Note that this method will generally not be called in scenarios + * that call for autodetection of parser type but rather, for situations + * where the user knows that the server uses a non-default configuration + * and knows what that configuration is. + *

+ * @param config A {@link FTPClientConfig FTPClientConfig} + * used to configure the parser created + * + * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. + * @exception ParserInitializationException + * Thrown on any exception in instantiation + * @since 1.4 + */ + public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) + throws ParserInitializationException + { + this.config = config; + String key = config.getServerSystemKey(); + return createFileEntryParser(key); + } + + + public FTPFileEntryParser createUnixFTPEntryParser() + { + return new UnixFTPEntryParser(); + } + + public FTPFileEntryParser createVMSVersioningFTPEntryParser() + { + return new VMSVersioningFTPEntryParser(); + } + + public FTPFileEntryParser createNetwareFTPEntryParser() { + return new NetwareFTPEntryParser(); + } + + public FTPFileEntryParser createNTFTPEntryParser() + { + if (config != null && FTPClientConfig.SYST_NT.equals( + config.getServerSystemKey())) + { + return new NTFTPEntryParser(); + } else { + return new CompositeFileEntryParser(new FTPFileEntryParser[] + { + new NTFTPEntryParser(), + new UnixFTPEntryParser() + }); + } + } + + public FTPFileEntryParser createOS2FTPEntryParser() + { + return new OS2FTPEntryParser(); + } + + public FTPFileEntryParser createOS400FTPEntryParser() + { + if (config != null && + FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) + { + return new OS400FTPEntryParser(); + } else { + return new CompositeFileEntryParser(new FTPFileEntryParser[] + { + new OS400FTPEntryParser(), + new UnixFTPEntryParser() + }); + } + } + + public FTPFileEntryParser createMVSEntryParser() + { + return new MVSFTPEntryParser(); + } + + + +} + diff --git a/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java b/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java new file mode 100644 index 0000000..c7e6da7 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.util.Calendar; + +import org.apache.commons.net.ftp.FTPFile; + +/** + * Parser for the Connect Enterprise Unix FTP Server From Sterling Commerce. + * Here is a sample of the sort of output line this parser processes: + * "-C--E-----FTP B QUA1I1 18128 41 Aug 12 13:56 QUADTEST" + *

+ * Note: EnterpriseUnixFTPEntryParser can only be instantiated through the + * DefaultFTPParserFactory by classname. It will not be chosen + * by the autodetection scheme. + * + * @version $Id: EnterpriseUnixFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @author Winston Ojeda + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + */ +public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl +{ + + /** + * months abbreviations looked for by this parser. Also used + * to determine which month has been matched by the parser. + */ + private static final String MONTHS = + "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; + + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "(([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])" + + "([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z]))" + + "(\\S*)\\s*" + + "(\\S+)\\s*" + + "(\\S*)\\s*" + + "(\\d*)\\s*" + + "(\\d*)\\s*" + + MONTHS + + "\\s*" + + "((?:[012]\\d*)|(?:3[01]))\\s*" + + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" + + "(\\S*)(\\s*.*)"; + + /** + * The sole constructor for a EnterpriseUnixFTPEntryParser object. + * + */ + public EnterpriseUnixFTPEntryParser() + { + super(REGEX); + } + + /** + * Parses a line of a unix FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If + * the file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + * + * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + + FTPFile file = new FTPFile(); + file.setRawListing(entry); + + if (matches(entry)) + { + String usr = group(14); + String grp = group(15); + String filesize = group(16); + String mo = group(17); + String da = group(18); + String yr = group(20); + String hr = group(21); + String min = group(22); + String name = group(23); + + file.setType(FTPFile.FILE_TYPE); + file.setUser(usr); + file.setGroup(grp); + try + { + file.setSize(Long.parseLong(filesize)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, + 0); + cal.set(Calendar.MINUTE, + 0); + cal.set(Calendar.HOUR_OF_DAY, + 0); + try + { + + int pos = MONTHS.indexOf(mo); + int month = pos / 4; + if (yr != null) + { + // it's a year + cal.set(Calendar.YEAR, + Integer.parseInt(yr)); + } + else + { + // it must be hour/minute or we wouldn't have matched + int year = cal.get(Calendar.YEAR); + + // if the month we're reading is greater than now, it must + // be last year + if (cal.get(Calendar.MONTH) < month) + { + year--; + } + cal.set(Calendar.YEAR, + year); + cal.set(Calendar.HOUR_OF_DAY, + Integer.parseInt(hr)); + cal.set(Calendar.MINUTE, + Integer.parseInt(min)); + } + cal.set(Calendar.MONTH, + month); + cal.set(Calendar.DATE, + Integer.parseInt(da)); + file.setTimestamp(cal); + } + catch (NumberFormatException e) + { + // do nothing, date will be uninitialized + } + file.setName(name); + + return file; + } + return null; + } +} diff --git a/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class b/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class new file mode 100644 index 0000000..f1bdf1b Binary files /dev/null and b/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class differ diff --git a/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java b/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java new file mode 100644 index 0000000..e80ec0d --- /dev/null +++ b/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFileEntryParser; + +/** + * The interface describes a factory for creating FTPFileEntryParsers. + * @since 1.2 + */ +public interface FTPFileEntryParserFactory +{ + /** + * Implementation should be a method that decodes the + * supplied key and creates an object implementing the + * interface FTPFileEntryParser. + * + * @param key A string that somehow identifies an + * FTPFileEntryParser to be created. + * + * @return the FTPFileEntryParser created. + * @exception ParserInitializationException + * Thrown on any exception in instantiation + */ + public FTPFileEntryParser createFileEntryParser(String key) + throws ParserInitializationException; + + /** + *

+ * Implementation should be a method that extracts + * a key from the supplied {@link FTPClientConfig FTPClientConfig} + * parameter and creates an object implementing the + * interface FTPFileEntryParser and uses the supplied configuration + * to configure it. + *

+ * Note that this method will generally not be called in scenarios + * that call for autodetection of parser type but rather, for situations + * where the user knows that the server uses a non-default configuration + * and knows what that configuration is. + *

+ * + * @param config A {@link FTPClientConfig FTPClientConfig} + * used to configure the parser created + * + * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. + * @exception ParserInitializationException + * Thrown on any exception in instantiation + * @since 1.4 + */ + public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) + throws ParserInitializationException; + +} diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParser.class b/org/apache/commons/net/ftp/parser/FTPTimestampParser.class new file mode 100644 index 0000000..32230d8 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/FTPTimestampParser.class differ diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParser.java b/org/apache/commons/net/ftp/parser/FTPTimestampParser.java new file mode 100644 index 0000000..40b46cb --- /dev/null +++ b/org/apache/commons/net/ftp/parser/FTPTimestampParser.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; +import java.util.Calendar; + +/** + * This interface specifies the concept of parsing an FTP server's + * timestamp. + * @since 1.4 + */ +public interface FTPTimestampParser { + + /** + * the default default date format. + */ + public static final String DEFAULT_SDF = UnixFTPEntryParser.DEFAULT_DATE_FORMAT; + /** + * the default recent date format. + */ + public static final String DEFAULT_RECENT_SDF = UnixFTPEntryParser.DEFAULT_RECENT_DATE_FORMAT; + + /** + * Parses the supplied datestamp parameter. This parameter typically would + * have been pulled from a longer FTP listing via the regular expression + * mechanism + * @param timestampStr - the timestamp portion of the FTP directory listing + * to be parsed + * @return a java.util.Calendar object initialized to the date + * parsed by the parser + * @throws ParseException if none of the parser mechanisms belonging to + * the implementor can parse the input. + */ + public Calendar parseTimestamp(String timestampStr) throws ParseException; + +} diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class b/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class new file mode 100644 index 0000000..0ae3067 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class differ diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java b/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java new file mode 100644 index 0000000..02a0cc8 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +import org.apache.commons.net.ftp.Configurable; +import org.apache.commons.net.ftp.FTPClientConfig; + +/** + * Default implementation of the {@link FTPTimestampParser FTPTimestampParser} + * interface also implements the {@link org.apache.commons.net.ftp.Configurable Configurable} + * interface to allow the parsing to be configured from the outside. + * + * @see ConfigurableFTPFileEntryParserImpl + * @since 1.4 + */ +public class FTPTimestampParserImpl implements + FTPTimestampParser, Configurable +{ + + + private SimpleDateFormat defaultDateFormat; + private SimpleDateFormat recentDateFormat; + private boolean lenientFutureDates = false; + + + /** + * The only constructor for this class. + */ + public FTPTimestampParserImpl() { + setDefaultDateFormat(DEFAULT_SDF); + setRecentDateFormat(DEFAULT_RECENT_SDF); + } + + /** + * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} + * in the {@link FTPTimestampParser FTPTimestampParser} interface + * according to this algorithm: + * + * If the recentDateFormat member has been defined, try to parse the + * supplied string with that. If that parse fails, or if the recentDateFormat + * member has not been defined, attempt to parse with the defaultDateFormat + * member. If that fails, throw a ParseException. + * + * This method allows a {@link Calendar} instance to be passed in which represents the + * current (system) time. + * + * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String) + * + * @param timestampStr The timestamp to be parsed + */ + public Calendar parseTimestamp(String timestampStr) throws ParseException { + Calendar now = Calendar.getInstance(); + return parseTimestamp(timestampStr, now); + } + + /** + * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} + * in the {@link FTPTimestampParser FTPTimestampParser} interface + * according to this algorithm: + * + * If the recentDateFormat member has been defined, try to parse the + * supplied string with that. If that parse fails, or if the recentDateFormat + * member has not been defined, attempt to parse with the defaultDateFormat + * member. If that fails, throw a ParseException. + * + * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String) + * @param timestampStr The timestamp to be parsed + * @param serverTime The current time for the server + * @since 1.5 + */ + public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { + Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it + now.setTimeZone(this.getServerTimeZone()); + Calendar working = (Calendar) now.clone(); + working.setTimeZone(getServerTimeZone()); + ParsePosition pp = new ParsePosition(0); + + Date parsed = null; + if (recentDateFormat != null) { + if (lenientFutureDates) { + // add a day to "now" so that "slop" doesn't cause a date + // slightly in the future to roll back a full year. (Bug 35181) + now.add(Calendar.DATE, 1); + } + parsed = recentDateFormat.parse(timestampStr, pp); + } + if (parsed != null && pp.getIndex() == timestampStr.length()) + { + working.setTime(parsed); + working.set(Calendar.YEAR, now.get(Calendar.YEAR)); + + if (working.after(now)) { + working.add(Calendar.YEAR, -1); + } + } else { + // Temporarily add the current year to the short date time + // to cope with short-date leap year strings. + // e.g. Java's DateFormatter will assume that "Feb 29 12:00" refers to + // Feb 29 1970 (an invalid date) rather than a potentially valid leap year date. + // This is pretty bad hack to work around the deficiencies of the JDK date/time classes. + if (recentDateFormat != null) { + pp = new ParsePosition(0); + int year = now.get(Calendar.YEAR); + String timeStampStrPlusYear = timestampStr + " " + year; + SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy", + recentDateFormat.getDateFormatSymbols()); + hackFormatter.setLenient(false); + hackFormatter.setTimeZone(recentDateFormat.getTimeZone()); + parsed = hackFormatter.parse(timeStampStrPlusYear, pp); + } + if (parsed != null && pp.getIndex() == timestampStr.length() + 5) { + working.setTime(parsed); + } + else { + pp = new ParsePosition(0); + parsed = defaultDateFormat.parse(timestampStr, pp); + // note, length checks are mandatory for us since + // SimpleDateFormat methods will succeed if less than + // full string is matched. They will also accept, + // despite "leniency" setting, a two-digit number as + // a valid year (e.g. 22:04 will parse as 22 A.D.) + // so could mistakenly confuse an hour with a year, + // if we don't insist on full length parsing. + if (parsed != null && pp.getIndex() == timestampStr.length()) { + working.setTime(parsed); + } else { + throw new ParseException( + "Timestamp could not be parsed with older or recent DateFormat", + pp.getIndex()); + } + } + } + return working; + } + + /** + * @return Returns the defaultDateFormat. + */ + public SimpleDateFormat getDefaultDateFormat() { + return defaultDateFormat; + } + /** + * @return Returns the defaultDateFormat pattern string. + */ + public String getDefaultDateFormatString() { + return defaultDateFormat.toPattern(); + } + /** + * @param defaultDateFormat The defaultDateFormat to be set. + */ + private void setDefaultDateFormat(String format) { + if (format != null) { + this.defaultDateFormat = new SimpleDateFormat(format); + this.defaultDateFormat.setLenient(false); + } + } + /** + * @return Returns the recentDateFormat. + */ + public SimpleDateFormat getRecentDateFormat() { + return recentDateFormat; + } + /** + * @return Returns the recentDateFormat. + */ + public String getRecentDateFormatString() { + return recentDateFormat.toPattern(); + } + /** + * @param recentDateFormat The recentDateFormat to set. + */ + private void setRecentDateFormat(String format) { + if (format != null) { + this.recentDateFormat = new SimpleDateFormat(format); + this.recentDateFormat.setLenient(false); + } + } + + /** + * @return returns an array of 12 strings representing the short + * month names used by this parse. + */ + public String[] getShortMonths() { + return defaultDateFormat.getDateFormatSymbols().getShortMonths(); + } + + + /** + * @return Returns the serverTimeZone used by this parser. + */ + public TimeZone getServerTimeZone() { + return this.defaultDateFormat.getTimeZone(); + } + /** + * sets a TimeZone represented by the supplied ID string into all + * of the parsers used by this server. + * @param serverTimeZone Time Id java.util.TimeZone id used by + * the ftp server. If null the client's local time zone is assumed. + */ + private void setServerTimeZone(String serverTimeZoneId) { + TimeZone serverTimeZone = TimeZone.getDefault(); + if (serverTimeZoneId != null) { + serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId); + } + this.defaultDateFormat.setTimeZone(serverTimeZone); + if (this.recentDateFormat != null) { + this.recentDateFormat.setTimeZone(serverTimeZone); + } + } + + /** + * Implementation of the {@link Configurable Configurable} + * interface. Configures this FTPTimestampParser according + * to the following logic: + *

+ * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat} + * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat} + * to values supplied in the config based on month names configured as follows: + *

    + *
  • If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString} + * has been supplied in the config, use that to parse parse timestamps.
  • + *
  • Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode} + * has been supplied in the config, use the month names represented + * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language} + * to parse timestamps.
  • + *
  • otherwise use default English month names
  • + *

+ * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId} + * has been supplied via the config, set that into all date formats that have + * been configured. + *

+ */ + public void configure(FTPClientConfig config) { + DateFormatSymbols dfs = null; + + String languageCode = config.getServerLanguageCode(); + String shortmonths = config.getShortMonthNames(); + if (shortmonths != null) { + dfs = FTPClientConfig.getDateFormatSymbols(shortmonths); + } else if (languageCode != null) { + dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode); + } else { + dfs = FTPClientConfig.lookupDateFormatSymbols("en"); + } + + + String recentFormatString = config.getRecentDateFormatStr(); + if (recentFormatString == null) { + this.recentDateFormat = null; + } else { + this.recentDateFormat = new SimpleDateFormat(recentFormatString, dfs); + this.recentDateFormat.setLenient(false); + } + + String defaultFormatString = config.getDefaultDateFormatStr(); + if (defaultFormatString == null) { + throw new IllegalArgumentException("defaultFormatString cannot be null"); + } + this.defaultDateFormat = new SimpleDateFormat(defaultFormatString, dfs); + this.defaultDateFormat.setLenient(false); + + setServerTimeZone(config.getServerTimeZoneId()); + + this.lenientFutureDates = config.isLenientFutureDates(); + } + /** + * @return Returns the lenientFutureDates. + */ + boolean isLenientFutureDates() { + return lenientFutureDates; + } + /** + * @param lenientFutureDates The lenientFutureDates to set. + */ + void setLenientFutureDates(boolean lenientFutureDates) { + this.lenientFutureDates = lenientFutureDates; + } +} diff --git a/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class b/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class new file mode 100644 index 0000000..0dc97d0 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java b/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java new file mode 100644 index 0000000..cd87e6e --- /dev/null +++ b/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java @@ -0,0 +1,495 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; +import java.util.List; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for IBM zOS/MVS + * Systems. + * + * @author Henrik Sorensen + * @author Jeff Nadler + * @author William Noto + * + * @version $Id: MVSFTPEntryParser.java 658520 2008-05-21 01:14:11Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for + * usage instructions) + */ +public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { + + static final int UNKNOWN_LIST_TYPE = -1; + static final int FILE_LIST_TYPE = 0; + static final int MEMBER_LIST_TYPE = 1; + static final int UNIX_LIST_TYPE = 2; + static final int JES_LEVEL_1_LIST_TYPE = 3; + static final int JES_LEVEL_2_LIST_TYPE = 4; + + private int isType = UNKNOWN_LIST_TYPE; + + /** + * Fallback parser for Unix-style listings + */ + private UnixFTPEntryParser unixFTPEntryParser; + + /** + * Dates are ignored for file lists, but are used for member lists where + * possible + */ + static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm"; // 2001/09/18 + // 13:52 + + /** + * Matches these entries: Volume Unit Referred Ext Used Recfm Lrecl BlkSz + * Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 80 PS MDI.OKL.WORK + * + */ + static final String FILE_LIST_REGEX = "\\S+\\s+" + // volume + // ignored + "\\S+\\s+" + // unit - ignored + "\\S+\\s+" + // access date - ignored + "\\S+\\s+" + // extents -ignored + "\\S+\\s+" + // used - ignored + "[FV]\\S*\\s+" + // recfm - must start with F or V + "\\S+\\s+" + // logical record length -ignored + "\\S+\\s+" + // block size - ignored + "(PS|PO|PO-E)\\s+" + // Dataset organisation. Many exist + // but only support: PS, PO, PO-E + "(\\S+)\\s*"; // Dataset Name (file name) + + /** + * Matches these entries: Name VV.MM Created Changed Size Init Mod Id + * TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 0 KIL001 + */ + static final String MEMBER_LIST_REGEX = "(\\S+)\\s+" + // name + "\\S+\\s+" + // version, modification (ignored) + "\\S+\\s+" + // create date (ignored) + "(\\S+)\\s+" + // modification date + "(\\S+)\\s+" + // modification time + "\\S+\\s+" + // size in lines (ignored) + "\\S+\\s+" + // size in lines at creation(ignored) + "\\S+\\s+" + // lines modified (ignored) + "\\S+\\s*"; // id of user who modified (ignored) + + /** + * Matches these entries, note: no header: IBMUSER1 JOB01906 OUTPUT 3 Spool + * Files 012345678901234567890123456789012345678901234 1 2 3 4 + */ + static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job + // name + // ignored + "(\\S+)\\s+" + // job number + "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) + "(\\S+)\\s+" + // number of spool files + "(\\S+)\\s+" + // Text "Spool" ignored + "(\\S+)\\s*" // Text "Files" ignored + ; + + /** + * JES INTERFACE LEVEL 2 parser Matches these entries: JOBNAME JOBID OWNER + * STATUS CLASS IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool files + * IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files + * 012345678901234567890123456789012345678901234 1 2 3 4 + * 012345678901234567890123456789012345678901234567890 + */ + + static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job + // name + // ignored + "(\\S+)\\s+" + // job number + "(\\S+)\\s+" + // owner ignored + "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored + "(\\S+)\\s+" + // job class ignored + "(\\S+).*" // rest ignored + ; + + /* + * --------------------------------------------------------------------- + * Very brief and incomplete description of the zOS/MVS-filesystem. (Note: + * "zOS" is the operating system on the mainframe, and is the new name for + * MVS) + * + * The filesystem on the mainframe does not have hierarchal structure as for + * example the unix filesystem. For a more comprehensive description, please + * refer to the IBM manuals + * + * @LINK: + * http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dgt2d440/CONTENTS + * + * + * Dataset names ============= + * + * A dataset name consist of a number of qualifiers separated by '.', each + * qualifier can be at most 8 characters, and the total length of a dataset + * can be max 44 characters including the dots. + * + * + * Dataset organisation ==================== + * + * A dataset represents a piece of storage allocated on one or more disks. + * The structure of the storage is described with the field dataset + * organinsation (DSORG). There are a number of dataset organisations, but + * only two are usable for FTP transfer. + * + * DSORG: PS: sequential, or flat file PO: partitioned dataset PO-E: + * extended partitioned dataset + * + * The PS file is just a flat file, as you would find it on the unix file + * system. + * + * The PO and PO-E files, can be compared to a single level directory + * structure. A PO file consist of a number of dataset members, or files if + * you will. It is possible to CD into the file, and to retrieve the + * individual members. + * + * + * Dataset record format ===================== + * + * The physical layout of the dataset is described on the dataset itself. + * There are a number of record formats (RECFM), but just a few is relavant + * for the FTP transfer. + * + * Any one beginning with either F or V can safely used by FTP transfer. All + * others should only be used with great care, so this version will just + * ignore the other record formats. F means a fixed number of records per + * allocated storage, and V means a variable number of records. + * + * + * Other notes =========== + * + * The file system supports automatically backup and retrieval of datasets. + * If a file is backed up, the ftp LIST command will return: ARCIVE Not + * Direct Access Device KJ.IOP998.ERROR.PL.UNITTEST + * + * + * Implementation notes ==================== + * + * Only datasets that have dsorg PS, PO or PO-E and have recfm beginning + * with F or V, is fully parsed. + * + * The following fields in FTPFile is used: FTPFile.Rawlisting: Always set. + * FTPFile.Type: DIRECTORY_TYPE or FILE_TYPE or UNKNOWN FTPFile.Name: name + * FTPFile.Timestamp: change time or null + * + * + * + * Additional information ====================== + * + * The MVS ftp server supports a number of features via the FTP interface. + * The features are controlled with the FTP command quote site filetype= + * SEQ is the default and used for normal file transfer JES is used to + * interact with the Job Entry Subsystem (JES) similar to a job scheduler + * DB2 is used to interact with a DB2 subsystem + * + * This parser supports SEQ and JES. + * + * + * + * + * + * + */ + + /** + * The sole constructor for a MVSFTPEntryParser object. + * + */ + public MVSFTPEntryParser() { + super(""); // note the regex is set in preParse. + super.configure(null); // configure parser with default configurations + } + + /** + * Parses a line of an z/OS - MVS FTP server file listing and converts it + * into a usable format in the form of an FTPFile instance. + * If the file listing line doesn't describe a file, then + * null is returned. Otherwise a FTPFile + * instance representing the file is returned. + * + * @param entry + * A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) { + boolean isParsed = false; + FTPFile f = new FTPFile(); + + if (isType == FILE_LIST_TYPE) + isParsed = parseFileList(f, entry); + else if (isType == MEMBER_LIST_TYPE) { + isParsed = parseMemberList(f, entry); + if (!isParsed) + isParsed = parseSimpleEntry(f, entry); + } else if (isType == UNIX_LIST_TYPE) { + isParsed = parseUnixList(f, entry); + } else if (isType == JES_LEVEL_1_LIST_TYPE) { + isParsed = parseJeslevel1List(f, entry); + } else if (isType == JES_LEVEL_2_LIST_TYPE) { + isParsed = parseJeslevel2List(f, entry); + } + + if (!isParsed) + f = null; + + return f; + } + + /** + * Parse entries representing a dataset list. Only datasets with DSORG PS or + * PO or PO-E and with RECFM F* or V* will be parsed. + * + * Format of ZOS/MVS file list: 1 2 3 4 5 6 7 8 9 10 Volume Unit Referred + * Ext Used Recfm Lrecl BlkSz Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 + * 80 PS MDI.OKL.WORK ARCIVE Not Direct Access Device + * KJ.IOP998.ERROR.PL.UNITTEST B1N231 3390 2006/03/20 1 15 VB 256 27998 PO + * PLU B1N231 3390 2006/03/20 1 15 VB 256 27998 PO-E PLB + * + * ----------------------------------- Group within Regex [1] Volume [2] + * Unit [3] Referred [4] Ext: number of extents [5] Used [6] Recfm: Record + * format [7] Lrecl: Logical record length [8] BlkSz: Block size [9] Dsorg: + * Dataset organisation. Many exists but only support: PS, PO, PO-E [10] + * Dsname: Dataset name + * + * Note: When volume is ARCIVE, it means the dataset is stored somewhere in + * a tape archive. These entries is currently not supported by this parser. + * A null value is returned. + * + * @param file + * will be updated with Name, Type, Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseFileList(FTPFile file, String entry) { + if (matches(entry)) { + file.setRawListing(entry); + String name = group(2); + String dsorg = group(1); + file.setName(name); + + // DSORG + if ("PS".equals(dsorg)) { + file.setType(FTPFile.FILE_TYPE); + } + else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) { + // regex already ruled out anything other than PO or PO-E + file.setType(FTPFile.DIRECTORY_TYPE); + } + else { + return false; + } + + return true; + } + + return false; + } + + /** + * Parse entries within a partitioned dataset. + * + * Format of a memberlist within a PDS: 1 2 3 4 5 6 7 8 9 Name VV.MM Created + * Changed Size Init Mod Id TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 + * 0 KIL001 TBTOOL 01.12 2002/09/12 2004/11/26 19:54 51 28 0 KIL001 + * + * ------------------------------------------- [1] Name [2] VV.MM: Version . + * modification [3] Created: yyyy / MM / dd [4,5] Changed: yyyy / MM / dd + * HH:mm [6] Size: number of lines [7] Init: number of lines when first + * created [8] Mod: number of modified lines a last save [9] Id: User id for + * last update + * + * + * @param file + * will be updated with Name, Type and Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseMemberList(FTPFile file, String entry) { + if (matches(entry)) { + file.setRawListing(entry); + String name = group(1); + String datestr = group(2) + " " + group(3); + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + try { + file.setTimestamp(super.parseTimestamp(datestr)); + } catch (ParseException e) { + e.printStackTrace(); + // just ignore parsing errors. + // TODO check this is ok + return false; // this is a parsing failure too. + } + return true; + } + + return false; + } + + /** + * Assigns the name to the first word of the entry. Only to be used from a + * safe context, for example from a memberlist, where the regex for some + * reason fails. Then just assign the name field of FTPFile. + * + * @param file + * @param entry + * @return + */ + private boolean parseSimpleEntry(FTPFile file, String entry) { + if (entry != null && entry.length() > 0) { + file.setRawListing(entry); + String name = entry.split(" ")[0]; + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + return true; + } + return false; + } + + /** + * Parse the entry as a standard unix file. Using the UnixFTPEntryParser. + * + * @param file + * @param entry + * @return true: entry is parsed, false: entry could not be parsed. + */ + private boolean parseUnixList(FTPFile file, String entry) { + file = unixFTPEntryParser.parseFTPEntry(entry); + if (file == null) + return false; + return true; + } + + /** + * Matches these entries, note: no header: [1] [2] [3] [4] [5] IBMUSER1 + * JOB01906 OUTPUT 3 Spool Files + * 012345678901234567890123456789012345678901234 1 2 3 4 + * ------------------------------------------- Group in regex [1] Job name + * [2] Job number [3] Job status (INPUT,ACTIVE,OUTPUT) [4] Number of sysout + * files [5] The string "Spool Files" + * + * + * @param file + * will be updated with Name, Type and Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseJeslevel1List(FTPFile file, String entry) { + if (matches(entry)) { + if (group(3).equalsIgnoreCase("OUTPUT")) { + file.setRawListing(entry); + String name = group(2); /* Job Number, used by GET */ + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + return true; + } + } + + return false; + } + + /** + * Matches these entries, note: no header: [1] [2] [3] [4] [5] JOBNAME JOBID + * OWNER STATUS CLASS IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool + * files IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files + * 012345678901234567890123456789012345678901234 1 2 3 4 + * ------------------------------------------- Group in regex [1] Job name + * [2] Job number [3] Owner [4] Job status (INPUT,ACTIVE,OUTPUT) [5] Job + * Class [6] The rest + * + * + * @param file + * will be updated with Name, Type and Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseJeslevel2List(FTPFile file, String entry) { + if (matches(entry)) { + if (group(4).equalsIgnoreCase("OUTPUT")) { + file.setRawListing(entry); + String name = group(2); /* Job Number, used by GET */ + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + return true; + } + } + + return false; + } + + /** + * preParse is called as part of the interface. Per definition is is called + * before the parsing takes place. Three kind of lists is recognize: + * z/OS-MVS File lists z/OS-MVS Member lists unix file lists + * @since 2.0 + */ + @Override + public List preParse(List orig) { + // simply remove the header line. Composite logic will take care of the + // two different types of + // list in short order. + if (orig != null && orig.size() > 0) { + String header = orig.get(0); + if (header.indexOf("Volume") >= 0 && header.indexOf("Dsname") >= 0) { + setType(FILE_LIST_TYPE); + super.setRegex(FILE_LIST_REGEX); + } else if (header.indexOf("Name") >= 0 && header.indexOf("Id") >= 0) { + setType(MEMBER_LIST_TYPE); + super.setRegex(MEMBER_LIST_REGEX); + } else if (header.indexOf("total") == 0) { + setType(UNIX_LIST_TYPE); + unixFTPEntryParser = new UnixFTPEntryParser(); + } else if (header.indexOf("Spool Files") >= 30) { + setType(JES_LEVEL_1_LIST_TYPE); + super.setRegex(JES_LEVEL_1_LIST_REGEX); + } else if (header.indexOf("JOBNAME") == 0 + && header.indexOf("JOBID") > 8) {// header contains JOBNAME JOBID OWNER // STATUS CLASS + setType(JES_LEVEL_2_LIST_TYPE); + super.setRegex(JES_LEVEL_2_LIST_REGEX); + } else { + setType(UNKNOWN_LIST_TYPE); + } + + if (isType != JES_LEVEL_1_LIST_TYPE) { // remove header is necessary + orig.remove(0); + } + } + + return orig; + } + + /** + * Explicitly set the type of listing being processed. + * @param type The listing type. + */ + void setType(int type) { + isType = type; + } + + /* + * @return + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig(FTPClientConfig.SYST_MVS, + DEFAULT_DATE_FORMAT, null, null, null, null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class b/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class new file mode 100644 index 0000000..bb3ed8f Binary files /dev/null and b/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java b/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java new file mode 100644 index 0000000..b6bc75e --- /dev/null +++ b/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for NT Systems. + * + * @author Winston Ojeda + * @author Steve Cohen + * @version $Id: NTFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + + private static final String DEFAULT_DATE_FORMAT + = "MM-dd-yy hh:mma"; //11-09-01 12:30PM + + + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "(\\S+)\\s+(\\S+)\\s+" + + "(?:()|([0-9]+))\\s+" + + "(\\S.*)"; + + /** + * The sole constructor for an NTFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public NTFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of an NTFTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public NTFTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + /** + * Parses a line of an NT FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + FTPFile f = new FTPFile(); + f.setRawListing(entry); + + if (matches(entry)) + { + String datestr = group(1)+" "+group(2); + String dirString = group(3); + String size = group(4); + String name = group(5); + try + { + f.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + if (null == name || name.equals(".") || name.equals("..")) + { + return (null); + } + f.setName(name); + + + if ("

".equals(dirString)) + { + f.setType(FTPFile.DIRECTORY_TYPE); + f.setSize(0); + } + else + { + f.setType(FTPFile.FILE_TYPE); + if (null != size) + { + f.setSize(Long.parseLong(size)); + } + } + return (f); + } + return null; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + public FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_NT, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class b/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class new file mode 100644 index 0000000..71babc5 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java b/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java new file mode 100644 index 0000000..3cbea82 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of the proprietary + * extensions for Novell-specific operations are not supported. See + * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html + * for more details. + * + * @author Rory Winston + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + * @version $Id: NetwareFTPEntryParser.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 1.5 + */ +public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { + + /** + * Default date format is e.g. Feb 22 2006 + */ + private static final String DEFAULT_DATE_FORMAT = "MMM dd yyyy"; + + /** + * Default recent date format is e.g. Feb 22 17:32 + */ + private static final String DEFAULT_RECENT_DATE_FORMAT = "MMM dd HH:mm"; + + /** + * this is the regular expression used by this parser. + * Example: d [-W---F--] SCION_VOL2 512 Apr 13 23:12 VOL2 + */ + private static final String REGEX = "(d|-){1}\\s+" // Directory/file flag + + "\\[(.*)\\]\\s+" // Attributes + + "(\\S+)\\s+" + "(\\d+)\\s+" // Owner and size + + "(\\S+\\s+\\S+\\s+((\\d+:\\d+)|(\\d{4})))" // Long/short date format + + "\\s+(.*)"; // Filename (incl. spaces) + + /** + * The default constructor for a NetwareFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public NetwareFTPEntryParser() { + this(null); + } + + /** + * This constructor allows the creation of an NetwareFTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public NetwareFTPEntryParser(FTPClientConfig config) { + super(REGEX); + configure(config); + } + + /** + * Parses a line of an NetwareFTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ *

+ * Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: + *

    + *
  • S - Supervisor; All rights. + *
  • R - Read; Right to open and read or execute. + *
  • W - Write; Right to open and modify. + *
  • C - Create; Right to create; when assigned to a file, allows a deleted file to be recovered. + *
  • E - Erase; Right to delete. + *
  • M - Modify; Right to rename a file and to change attributes. + *
  • F - File Scan; Right to see directory or file listings. + *
  • A - Access Control; Right to modify trustee assignments and the Inherited Rights Mask. + *
+ * + * See here + * for more details + * + * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) { + + FTPFile f = new FTPFile(); + if (matches(entry)) { + String dirString = group(1); + String attrib = group(2); + String user = group(3); + String size = group(4); + String datestr = group(5); + String name = group(9); + + try { + f.setTimestamp(super.parseTimestamp(datestr)); + } catch (ParseException e) { + // intentionally do nothing + } + + //is it a DIR or a file + if (dirString.trim().equals("d")) { + f.setType(FTPFile.DIRECTORY_TYPE); + } else // Should be "-" + { + f.setType(FTPFile.FILE_TYPE); + } + + f.setUser(user); + + //set the name + f.setName(name.trim()); + + //set the size + f.setSize(Long.parseLong(size.trim())); + + // Now set the permissions (or at least a subset thereof - full permissions would probably require + // subclassing FTPFile and adding extra metainformation there) + if (attrib.indexOf("R") != -1) { + f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, + true); + } + if (attrib.indexOf("W") != -1) { + f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, + true); + } + + return (f); + } + return null; + + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, + DEFAULT_DATE_FORMAT, DEFAULT_RECENT_DATE_FORMAT, null, null, + null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class b/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class new file mode 100644 index 0000000..332ae30 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java b/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java new file mode 100644 index 0000000..dc02ffb --- /dev/null +++ b/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for OS2 Systems. + * + * @author Winston Ojeda + * @author Steve Cohen + * @version $Id: OS2FTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl + +{ + + private static final String DEFAULT_DATE_FORMAT + = "MM-dd-yy HH:mm"; //11-09-01 12:30 + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "\\s*([0-9]+)\\s*" + + "(\\s+|[A-Z]+)\\s*" + + "(DIR|\\s+)\\s*" + + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ + + "(\\S.*)"; + + /** + * The default constructor for a OS2FTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public OS2FTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of an OS2FTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public OS2FTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + /** + * Parses a line of an OS2 FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + + FTPFile f = new FTPFile(); + if (matches(entry)) + { + String size = group(1); + String attrib = group(2); + String dirString = group(3); + String datestr = group(4)+" "+group(5); + String name = group(6); + try + { + f.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + //is it a DIR or a file + if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) + { + f.setType(FTPFile.DIRECTORY_TYPE); + } + else + { + f.setType(FTPFile.FILE_TYPE); + } + + + //set the name + f.setName(name.trim()); + + //set the size + f.setSize(Long.parseLong(size.trim())); + + return (f); + } + return null; + + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_OS2, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class b/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class new file mode 100644 index 0000000..b77795b Binary files /dev/null and b/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java b/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java new file mode 100644 index 0000000..66c370b --- /dev/null +++ b/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * @version $Id: OS400FTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + */ + +public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + private static final String DEFAULT_DATE_FORMAT + = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24 + + + + private static final String REGEX = + "(\\S+)\\s+" // user + + "(\\d+)\\s+" // size + + "(\\S+)\\s+(\\S+)\\s+" // date stuff + + "(\\*\\S+)\\s+" // *STMF/*DIR + + "(\\S+/?)\\s*"; // filename + + + /** + * The default constructor for a OS400FTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public OS400FTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of an OS400FTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public OS400FTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + + public FTPFile parseFTPEntry(String entry) + { + + FTPFile file = new FTPFile(); + file.setRawListing(entry); + int type; + + if (matches(entry)) + { + String usr = group(1); + String filesize = group(2); + String datestr = group(3)+" "+group(4); + String typeStr = group(5); + String name = group(6); + + try + { + file.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + if (typeStr.equalsIgnoreCase("*STMF")) + { + type = FTPFile.FILE_TYPE; + } + else if (typeStr.equalsIgnoreCase("*DIR")) + { + type = FTPFile.DIRECTORY_TYPE; + } + else + { + type = FTPFile.UNKNOWN_TYPE; + } + + file.setType(type); + + file.setUser(usr); + + try + { + file.setSize(Long.parseLong(filesize)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + + if (name.endsWith("/")) + { + name = name.substring(0, name.length() - 1); + } + int pos = name.lastIndexOf('/'); + if (pos > -1) + { + name = name.substring(pos + 1); + } + + file.setName(name); + + return file; + } + return null; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_OS400, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/ParserInitializationException.class b/org/apache/commons/net/ftp/parser/ParserInitializationException.class new file mode 100644 index 0000000..4f7fb6f Binary files /dev/null and b/org/apache/commons/net/ftp/parser/ParserInitializationException.class differ diff --git a/org/apache/commons/net/ftp/parser/ParserInitializationException.java b/org/apache/commons/net/ftp/parser/ParserInitializationException.java new file mode 100644 index 0000000..8af9261 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/ParserInitializationException.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +/** + * This class encapsulates all errors that may be thrown by + * the process of an FTPFileEntryParserFactory creating and + * instantiating an FTPFileEntryParser. + */ +public class ParserInitializationException extends RuntimeException { + + /** + * Root exception that caused this to be thrown + */ + private final Throwable rootCause; + + /** + * Constucts a ParserInitializationException with just a message + * + * @param message Exception message + */ + public ParserInitializationException(String message) { + super(message); + this.rootCause = null; + } + + /** + * Constucts a ParserInitializationException with a message + * and a root cause. + * + * @param message Exception message + * @param rootCause root cause throwable that caused + * this to be thrown + */ + public ParserInitializationException(String message, Throwable rootCause) { + super(message); + this.rootCause = rootCause; + } + + /** + * returns the root cause of this exception or null + * if no root cause was specified. + * + * @return the root cause of this exception being thrown + */ + public Throwable getRootCause() { + return this.rootCause; + } + +} diff --git a/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class b/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class new file mode 100644 index 0000000..3cd32f0 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class differ diff --git a/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java b/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java new file mode 100644 index 0000000..5277444 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.net.ftp.parser; + +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.commons.net.ftp.FTPFileEntryParserImpl; + +/** + * This abstract class implements both the older FTPFileListParser and + * newer FTPFileEntryParser interfaces with default functionality. + * All the classes in the parser subpackage inherit from this. + * + * This is the base for all regular based FTPFileEntryParser + * + * @author Steve Cohen + */ +public abstract class RegexFTPFileEntryParserImpl extends + FTPFileEntryParserImpl { + /** + * internal pattern the matcher tries to match, representing a file + * entry + */ + private Pattern pattern = null; + + /** + * internal match result used by the parser + */ + private MatchResult result = null; + + /** + * Internal PatternMatcher object used by the parser. It has protected + * scope in case subclasses want to make use of it for their own purposes. + */ + protected Matcher _matcher_ = null; + + /** + * The constructor for a RegexFTPFileEntryParserImpl object. + * + * @param regex The regular expression with which this object is + * initialized. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen in + * normal conditions. It it is seen, this is a sign that a subclass has + * been created with a bad regular expression. Since the parser must be + * created before use, this means that any bad parser subclasses created + * from this will bomb very quickly, leading to easy detection. + */ + + public RegexFTPFileEntryParserImpl(String regex) { + super(); + setRegex(regex); + } + + /** + * Convenience method delegates to the internal MatchResult's matches() + * method. + * + * @param s the String to be matched + * @return true if s matches this object's regular expression. + */ + + public boolean matches(String s) { + this.result = null; + _matcher_ = pattern.matcher(s); + if (_matcher_.matches()) { + this.result = _matcher_.toMatchResult(); + } + return null != this.result; + } + + /** + * Convenience method + * + * @return the number of groups() in the internal MatchResult. + */ + + public int getGroupCnt() { + if (this.result == null) { + return 0; + } + return this.result.groupCount(); + } + + /** + * Convenience method delegates to the internal MatchResult's group() + * method. + * + * @param matchnum match group number to be retrieved + * + * @return the content of the matchnum'th group of the internal + * match or null if this method is called without a match having + * been made. + */ + public String group(int matchnum) { + if (this.result == null) { + return null; + } + return this.result.group(matchnum); + } + + /** + * For debugging purposes - returns a string shows each match group by + * number. + * + * @return a string shows each match group by number. + */ + + public String getGroupsAsString() { + StringBuffer b = new StringBuffer(); + for (int i = 1; i <= this.result.groupCount(); i++) { + b.append(i).append(") ").append(this.result.group(i)).append( + System.getProperty("line.separator")); + } + return b.toString(); + } + + /** + * Alter the current regular expression being utilised for entry parsing + * and create a new {@link Pattern} instance. + * @param regex The new regular expression + * @return + * @since 2.0 + */ + public boolean setRegex(String regex) { + try { + pattern = Pattern.compile(regex); + } catch (PatternSyntaxException pse) { + throw new IllegalArgumentException("Unparseable regex supplied: " + + regex); + } + return (pattern != null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class b/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class new file mode 100644 index 0000000..27a082b Binary files /dev/null and b/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java b/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java new file mode 100644 index 0000000..2a2a909 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java @@ -0,0 +1,295 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation FTPFileEntryParser and FTPFileListParser for standard + * Unix Systems. + * + * This class is based on the logic of Daniel Savarese's + * DefaultFTPListParser, but adapted to use regular expressions and to fit the + * new FTPFileEntryParser interface. + * @version $Id: UnixFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + + static final String DEFAULT_DATE_FORMAT + = "MMM d yyyy"; //Nov 9 2001 + + static final String DEFAULT_RECENT_DATE_FORMAT + = "MMM d HH:mm"; //Nov 9 20:06 + + static final String NUMERIC_DATE_FORMAT + = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06 + + /** + * Some Linux distributions are now shipping an FTP server which formats + * file listing dates in an all-numeric format: + * "yyyy-MM-dd HH:mm. + * This is a very welcome development, and hopefully it will soon become + * the standard. However, since it is so new, for now, and possibly + * forever, we merely accomodate it, but do not make it the default. + *

+ * For now end users may specify this format only via + * UnixFTPEntryParser(FTPClientConfig). + * Steve Cohen - 2005-04-17 + */ + public static final FTPClientConfig NUMERIC_DATE_CONFIG = + new FTPClientConfig( + FTPClientConfig.SYST_UNIX, + NUMERIC_DATE_FORMAT, + null, null, null, null); + + /** + * this is the regular expression used by this parser. + * + * Permissions: + * r the file is readable + * w the file is writable + * x the file is executable + * - the indicated permission is not granted + * L mandatory locking occurs during access (the set-group-ID bit is + * on and the group execution bit is off) + * s the set-user-ID or set-group-ID bit is on, and the corresponding + * user or group execution bit is also on + * S undefined bit-state (the set-user-ID bit is on and the user + * execution bit is off) + * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and + * execution is on + * T the 1000 bit is turned on, and execution is off (undefined bit- + * state) + * e z/OS external link bit + */ + private static final String REGEX = + "([bcdelfmpSs-])" + +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" + + "(\\d+)\\s+" + + "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces) + + "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces) + + "(\\d+(?:,\\s*\\d+)?)\\s+" + + /* + numeric or standard format date + */ + + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+))\\s+" + + /* + year (for non-recent standard format) + or time (for numeric or recent standard format + */ + + "(\\d+(?::\\d+)?)\\s+" + + + "(\\S*)(\\s*.*)"; + + + /** + * The default constructor for a UnixFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public UnixFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of a UnixFTPEntryParser object with + * something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public UnixFTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + + /** + * Parses a line of a unix (standard) FTP server file listing and converts + * it into a usable format in the form of an FTPFile + * instance. If the file listing line doesn't describe a file, + * null is returned, otherwise a FTPFile + * instance representing the files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) { + FTPFile file = new FTPFile(); + file.setRawListing(entry); + int type; + boolean isDevice = false; + + if (matches(entry)) + { + String typeStr = group(1); + String hardLinkCount = group(15); + String usr = group(16); + String grp = group(17); + String filesize = group(18); + String datestr = group(19) + " " + group(20); + String name = group(21); + String endtoken = group(22); + + try + { + file.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + // bcdlfmpSs- + switch (typeStr.charAt(0)) + { + case 'd': + type = FTPFile.DIRECTORY_TYPE; + break; + case 'e': + type = FTPFile.SYMBOLIC_LINK_TYPE; + break; + case 'l': + type = FTPFile.SYMBOLIC_LINK_TYPE; + break; + case 'b': + case 'c': + isDevice = true; + // break; - fall through + case 'f': + case '-': + type = FTPFile.FILE_TYPE; + break; + default: + type = FTPFile.UNKNOWN_TYPE; + } + + file.setType(type); + + int g = 4; + for (int access = 0; access < 3; access++, g += 4) + { + // Use != '-' to avoid having to check for suid and sticky bits + file.setPermission(access, FTPFile.READ_PERMISSION, + (!group(g).equals("-"))); + file.setPermission(access, FTPFile.WRITE_PERMISSION, + (!group(g + 1).equals("-"))); + + String execPerm = group(g + 2); + if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) + { + file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); + } + else + { + file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); + } + } + + if (!isDevice) + { + try + { + file.setHardLinkCount(Integer.parseInt(hardLinkCount)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + } + + file.setUser(usr); + file.setGroup(grp); + + try + { + file.setSize(Long.parseLong(filesize)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + + if (null == endtoken) + { + file.setName(name); + } + else + { + // oddball cases like symbolic links, file names + // with spaces in them. + name += endtoken; + if (type == FTPFile.SYMBOLIC_LINK_TYPE) + { + + int end = name.indexOf(" -> "); + // Give up if no link indicator is present + if (end == -1) + { + file.setName(name); + } + else + { + file.setName(name.substring(0, end)); + file.setLink(name.substring(end + 4)); + } + + } + else + { + file.setName(name); + } + } + return file; + } + return null; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_UNIX, + DEFAULT_DATE_FORMAT, + DEFAULT_RECENT_DATE_FORMAT, + null, null, null); + } + +} diff --git a/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class b/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class new file mode 100644 index 0000000..ee8d5f3 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java b/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java new file mode 100644 index 0000000..1e55ede --- /dev/null +++ b/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; +import java.util.StringTokenizer; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPListParseEngine; + +/** + * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. + * This is a sample of VMS LIST output + * + * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + *

+ * Note: VMSFTPEntryParser can only be instantiated through the + * DefaultFTPParserFactory by classname. It will not be chosen + * by the autodetection scheme. + * + *

+ * + * @author Winston Ojeda + * @author Steve Cohen + * @author Stephane ESTE-GRACIAS + * @version $Id: VMSFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + */ +public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + + private static final String DEFAULT_DATE_FORMAT + = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24 + + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "(.*;[0-9]+)\\s*" //1 file and version + + "(\\d+)/\\d+\\s*" //2 size/allocated + +"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time + + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner + + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; //9,10,11 Permissions (O,G,W) + // TODO - perhaps restrict permissions to [RWED]* ? + + + + /** + * Constructor for a VMSFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public VMSFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of a VMSFTPEntryParser object with + * something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public VMSFTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + + + /*** + * Parses an FTP server file listing and converts it into a usable format + * in the form of an array of FTPFile instances. If the + * file list contains no files, null should be + * returned, otherwise an array of FTPFile instances + * representing the files in the directory is returned. + *

+ * @param listStream The InputStream from which the file list should be + * read. + * @return The list of file information contained in the given path. null + * if the list could not be obtained or if there are no files in + * the directory. + * @exception IOException If an I/O error occurs reading the listStream. + ***/ + public FTPFile[] parseFileList(InputStream listStream) throws IOException { + FTPListParseEngine engine = new FTPListParseEngine(this); + engine.readServerList(listStream); + return engine.getFiles(); + } + + + + /** + * Parses a line of a VMS FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + //one block in VMS equals 512 bytes + long longBlock = 512; + + if (matches(entry)) + { + FTPFile f = new FTPFile(); + f.setRawListing(entry); + String name = group(1); + String size = group(2); + String datestr = group(3)+" "+group(4); + String owner = group(5); + String permissions[] = new String[3]; + permissions[0]= group(9); + permissions[1]= group(10); + permissions[2]= group(11); + try + { + f.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + String grp; + String user; + StringTokenizer t = new StringTokenizer(owner, ","); + switch (t.countTokens()) { + case 1: + grp = null; + user = t.nextToken(); + break; + case 2: + grp = t.nextToken(); + user = t.nextToken(); + break; + default: + grp = null; + user = null; + } + + if (name.lastIndexOf(".DIR") != -1) + { + f.setType(FTPFile.DIRECTORY_TYPE); + } + else + { + f.setType(FTPFile.FILE_TYPE); + } + //set FTPFile name + //Check also for versions to be returned or not + if (isVersioning()) + { + f.setName(name); + } + else + { + name = name.substring(0, name.lastIndexOf(";")); + f.setName(name); + } + //size is retreived in blocks and needs to be put in bytes + //for us humans and added to the FTPFile array + long sizeInBytes = Long.parseLong(size) * longBlock; + f.setSize(sizeInBytes); + + f.setGroup(grp); + f.setUser(user); + //set group and owner + + //Set file permission. + //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain + //R (read) W (write) E (execute) D (delete) + + //iterate for OWNER GROUP WORLD permissions + for (int access = 0; access < 3; access++) + { + String permission = permissions[access]; + + f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); + f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); + f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); + } + + return f; + } + return null; + } + + + /** + * Reads the next entry using the supplied BufferedReader object up to + * whatever delemits one entry from the next. This parser cannot use + * the default implementation of simply calling BufferedReader.readLine(), + * because one entry may span multiple lines. + * + * @param reader The BufferedReader object from which entries are to be + * read. + * + * @return A string representing the next ftp entry or null if none found. + * @exception IOException thrown on any IO Error reading from the reader. + */ + @Override + public String readNextEntry(BufferedReader reader) throws IOException + { + String line = reader.readLine(); + StringBuffer entry = new StringBuffer(); + while (line != null) + { + if (line.startsWith("Directory") || line.startsWith("Total")) { + line = reader.readLine(); + continue; + } + + entry.append(line); + if (line.trim().endsWith(")")) + { + break; + } + line = reader.readLine(); + } + return (entry.length() == 0 ? null : entry.toString()); + } + + protected boolean isVersioning() { + return false; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_VMS, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class new file mode 100644 index 0000000..fd27f2a Binary files /dev/null and b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class differ diff --git a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class new file mode 100644 index 0000000..c0e20b6 Binary files /dev/null and b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class differ diff --git a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java new file mode 100644 index 0000000..cb25709 --- /dev/null +++ b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.commons.net.ftp.FTPClientConfig; + +/** + * Special implementation VMSFTPEntryParser with versioning turned on. + * This parser removes all duplicates and only leaves the version with the highest + * version number for each filename. + * + * This is a sample of VMS LIST output + * + * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + *

+ * + * @author Winston Ojeda + * @author Stephane ESTE-GRACIAS + * @version $Id: VMSVersioningFTPEntryParser.java 636854 2008-03-13 19:55:01Z sebb $ + * + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser +{ + + private Matcher _preparse_matcher_; + private Pattern _preparse_pattern_; + private static final String PRE_PARSE_REGEX = + "(.*);([0-9]+)\\s*.*"; + + /** + * Constructor for a VMSFTPEntryParser object. Sets the versioning member + * to the supplied value. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public VMSVersioningFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of a VMSVersioningFTPEntryParser + * object with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public VMSVersioningFTPEntryParser(FTPClientConfig config) + { + super(); + configure(config); + try + { + //_preparse_matcher_ = new Perl5Matcher(); + _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); + } + catch (PatternSyntaxException pse) + { + throw new IllegalArgumentException ( + "Unparseable regex supplied: " + PRE_PARSE_REGEX); + } + + } + + + + private static class NameVersion { + String name; + int versionNumber; + NameVersion(String name, String vers) { + this.name = name; + this.versionNumber = Integer.parseInt(vers); + } + } + + /** + * Implement hook provided for those implementers (such as + * VMSVersioningFTPEntryParser, and possibly others) which return + * multiple files with the same name to remove the duplicates .. + * + * @param original Original list + * + * @return Original list purged of duplicates + */ + @Override + public List preParse(List original) { + original = super.preParse(original); + HashMap existingEntries = new HashMap(); + ListIterator iter = original.listIterator(); + while (iter.hasNext()) { + String entry = iter.next().trim(); + MatchResult result = null; + _preparse_matcher_ = _preparse_pattern_.matcher(entry); + if (_preparse_matcher_.matches()) { + result = _preparse_matcher_.toMatchResult(); + String name = result.group(1); + String version = result.group(2); + NameVersion nv = new NameVersion(name, version); + NameVersion existing = existingEntries.get(name); + if (null != existing) { + if (nv.versionNumber < existing.versionNumber) { + iter.remove(); // removal removes from original list. + continue; + } + } + existingEntries.put(name, nv); + } + + } + // we've now removed all entries less than with less than the largest + // version number for each name that were listed after the largest. + // we now must remove those with smaller than the largest version number + // for each name that were found before the largest + while (iter.hasPrevious()) { + String entry = iter.previous().trim(); + MatchResult result = null; + _preparse_matcher_ = _preparse_pattern_.matcher(entry); + if (_preparse_matcher_.matches()) { + result = _preparse_matcher_.toMatchResult(); + String name = result.group(1); + String version = result.group(2); + NameVersion nv = new NameVersion(name, version); + NameVersion existing = existingEntries.get(name); + if (null != existing) { + if (nv.versionNumber < existing.versionNumber) { + iter.remove(); // removal removes from original list. + } + } + } + + } + return original; + } + + + @Override + protected boolean isVersioning() { + return true; + } + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/io/CopyStreamAdapter.java b/org/apache/commons/net/io/CopyStreamAdapter.java new file mode 100644 index 0000000..0679d23 --- /dev/null +++ b/org/apache/commons/net/io/CopyStreamAdapter.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.util.EventListener; + +import org.apache.commons.net.util.ListenerList; + +/** + * The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners + * when either of its bytesTransferred() methods are called. Its purpose + * is to facilitate the notification of the progress of a copy operation + * performed by one of the static copyStream() methods in + * org.apache.commons.io.Util to multiple listeners. The static + * copyStream() methods invoke the + * bytesTransfered(long, int) of a CopyStreamListener for performance + * reasons and also because multiple listeners cannot be registered given + * that the methods are static. + *

+ *

+ * @see CopyStreamEvent + * @see CopyStreamListener + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamAdapter.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public class CopyStreamAdapter implements CopyStreamListener +{ + private ListenerList internalListeners; + + /** + * Creates a new copyStreamAdapter. + */ + public CopyStreamAdapter() + { + internalListeners = new ListenerList(); + } + + /** + * This method is invoked by a CopyStreamEvent source after copying + * a block of bytes from a stream. The CopyStreamEvent will contain + * the total number of bytes transferred so far and the number of bytes + * transferred in the last write. The CopyStreamAdapater will relay + * the event to all of its registered listeners, listing itself as the + * source of the event. + * @param event The CopyStreamEvent fired by the copying of a block of + * bytes. + */ + public void bytesTransferred(CopyStreamEvent event) + { + bytesTransferred(event.getTotalBytesTransferred(), + event.getBytesTransferred(), + event.getStreamSize()); + } + + /** + * This method is not part of the JavaBeans model and is used by the + * static methods in the org.apache.commons.io.Util class for efficiency. + * It is invoked after a block of bytes to inform the listener of the + * transfer. The CopyStreamAdapater will create a CopyStreamEvent + * from the arguments and relay the event to all of its registered + * listeners, listing itself as the source of the event. + * @param totalBytesTransferred The total number of bytes transferred + * so far by the copy operation. + * @param bytesTransferred The number of bytes copied by the most recent + * write. + * @param streamSize The number of bytes in the stream being copied. + * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if + * the size is unknown. + */ + public void bytesTransferred(long totalBytesTransferred, + int bytesTransferred, long streamSize) + { + CopyStreamEvent event; + + event = new CopyStreamEvent(this, + totalBytesTransferred, + bytesTransferred, + streamSize); + + for (EventListener listener : internalListeners) + { + ((CopyStreamListener) (listener)).bytesTransferred(event); + } + } + + /** + * Registers a CopyStreamListener to receive CopyStreamEvents. + * Although this method is not declared to be synchronized, it is + * implemented in a thread safe manner. + * @param listener The CopyStreamlistener to register. + */ + public void addCopyStreamListener(CopyStreamListener listener) + { + internalListeners.addListener(listener); + } + + /** + * Unregisters a CopyStreamListener. Although this method is not + * synchronized, it is implemented in a thread safe manner. + * @param listener The CopyStreamlistener to unregister. + */ + public void removeCopyStreamListener(CopyStreamListener listener) + { + internalListeners.removeListener(listener); + } +} diff --git a/org/apache/commons/net/io/CopyStreamEvent.class b/org/apache/commons/net/io/CopyStreamEvent.class new file mode 100644 index 0000000..66d719c Binary files /dev/null and b/org/apache/commons/net/io/CopyStreamEvent.class differ diff --git a/org/apache/commons/net/io/CopyStreamEvent.java b/org/apache/commons/net/io/CopyStreamEvent.java new file mode 100644 index 0000000..d7d0ec3 --- /dev/null +++ b/org/apache/commons/net/io/CopyStreamEvent.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.util.EventObject; + +/** + * A CopyStreamEvent is triggered after every write performed by a + * stream copying operation. The event stores the number of bytes + * transferred by the write triggering the event as well as the total + * number of bytes transferred so far by the copy operation. + *

+ *

+ * @see CopyStreamListener + * @see CopyStreamAdapter + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamEvent.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public class CopyStreamEvent extends EventObject +{ + /** + * Constant used to indicate the stream size is unknown. + */ + public static final long UNKNOWN_STREAM_SIZE = -1; + + private int bytesTransferred; + private long totalBytesTransferred; + private long streamSize; + + /** + * Creates a new CopyStreamEvent instance. + * @param source The source of the event. + * @param totalBytesTransferred The total number of bytes transferred so + * far during a copy operation. + * @param bytesTransferred The number of bytes transferred during the + * write that triggered the CopyStreamEvent. + * @param streamSize The number of bytes in the stream being copied. + * This may be set to UNKNOWN_STREAM_SIZE if the + * size is unknown. + */ + public CopyStreamEvent(Object source, long totalBytesTransferred, + int bytesTransferred, long streamSize) + { + super(source); + this.bytesTransferred = bytesTransferred; + this.totalBytesTransferred = totalBytesTransferred; + this.streamSize = streamSize; + } + + /** + * Returns the number of bytes transferred by the write that triggered + * the event. + * @return The number of bytes transferred by the write that triggered + * the vent. + */ + public int getBytesTransferred() + { + return bytesTransferred; + } + + /** + * Returns the total number of bytes transferred so far by the copy + * operation. + * @return The total number of bytes transferred so far by the copy + * operation. + */ + public long getTotalBytesTransferred() + { + return totalBytesTransferred; + } + + /** + * Returns the size of the stream being copied. + * This may be set to UNKNOWN_STREAM_SIZE if the + * size is unknown. + * @return The size of the stream being copied. + */ + public long getStreamSize() + { + return streamSize; + } +} diff --git a/org/apache/commons/net/io/CopyStreamException.class b/org/apache/commons/net/io/CopyStreamException.class new file mode 100644 index 0000000..adf2ebb Binary files /dev/null and b/org/apache/commons/net/io/CopyStreamException.class differ diff --git a/org/apache/commons/net/io/CopyStreamException.java b/org/apache/commons/net/io/CopyStreamException.java new file mode 100644 index 0000000..8d34145 --- /dev/null +++ b/org/apache/commons/net/io/CopyStreamException.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; + +/** + * The CopyStreamException class is thrown by the org.apache.commons.io.Util + * copyStream() methods. It stores the number of bytes confirmed to + * have been transferred before an I/O error as well as the IOException + * responsible for the failure of a copy operation. + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamException.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public class CopyStreamException extends IOException +{ + private long totalBytesTransferred; + private IOException ioException; + + /** + * Creates a new CopyStreamException instance. + * @param message A message describing the error. + * @param bytesTransferred The total number of bytes transferred before + * an exception was thrown in a copy operation. + * @param exception The IOException thrown during a copy operation. + */ + public CopyStreamException(String message, + long bytesTransferred, + IOException exception) + { + super(message); + totalBytesTransferred = bytesTransferred; + ioException = exception; + } + + /** + * Returns the total number of bytes confirmed to have + * been transferred by a failed copy operation. + * @return The total number of bytes confirmed to have + * been transferred by a failed copy operation. + */ + public long getTotalBytesTransferred() + { + return totalBytesTransferred; + } + + /** + * Returns the IOException responsible for the failure of a copy operation. + * @return The IOException responsible for the failure of a copy operation. + */ + public IOException getIOException() + { + return ioException; + } +} diff --git a/org/apache/commons/net/io/CopyStreamListener.class b/org/apache/commons/net/io/CopyStreamListener.class new file mode 100644 index 0000000..3d5bb08 Binary files /dev/null and b/org/apache/commons/net/io/CopyStreamListener.class differ diff --git a/org/apache/commons/net/io/CopyStreamListener.java b/org/apache/commons/net/io/CopyStreamListener.java new file mode 100644 index 0000000..9e97fb9 --- /dev/null +++ b/org/apache/commons/net/io/CopyStreamListener.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.util.EventListener; + +/** + * The CopyStreamListener class can accept CopyStreamEvents to keep track + * of the progress of a stream copying operation. However, it is currently + * not used that way within NetComponents for performance reasons. Rather + * the bytesTransferred(long, int) method is called directly rather than + * passing an event to bytesTransferred(CopyStreamEvent), saving the creation + * of a CopyStreamEvent instance. Also, the only place where + * CopyStreamListener is currently used within NetComponents is in the + * static methods of the uninstantiable org.apache.commons.io.Util class, which + * would preclude the use of addCopyStreamListener and + * removeCopyStreamListener methods. However, future additions may use the + * JavaBean event model, which is why the hooks have been included from the + * beginning. + *

+ *

+ * @see CopyStreamEvent + * @see CopyStreamAdapter + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamListener.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public interface CopyStreamListener extends EventListener +{ + /** + * This method is invoked by a CopyStreamEvent source after copying + * a block of bytes from a stream. The CopyStreamEvent will contain + * the total number of bytes transferred so far and the number of bytes + * transferred in the last write. + * @param event The CopyStreamEvent fired by the copying of a block of + * bytes. + */ + public void bytesTransferred(CopyStreamEvent event); + + + /** + * This method is not part of the JavaBeans model and is used by the + * static methods in the org.apache.commons.io.Util class for efficiency. + * It is invoked after a block of bytes to inform the listener of the + * transfer. + * @param totalBytesTransferred The total number of bytes transferred + * so far by the copy operation. + * @param bytesTransferred The number of bytes copied by the most recent + * write. + * @param streamSize The number of bytes in the stream being copied. + * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if + * the size is unknown. + */ + public void bytesTransferred(long totalBytesTransferred, + int bytesTransferred, + long streamSize); +} diff --git a/org/apache/commons/net/io/DotTerminatedMessageReader.java b/org/apache/commons/net/io/DotTerminatedMessageReader.java new file mode 100644 index 0000000..c0f344d --- /dev/null +++ b/org/apache/commons/net/io/DotTerminatedMessageReader.java @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.PushbackReader; +import java.io.Reader; + +/** + * DotTerminatedMessageReader is a class used to read messages from a + * server that are terminated by a single dot followed by a + * <CR><LF> + * sequence and with double dots appearing at the begining of lines which + * do not signal end of message yet start with a dot. Various Internet + * protocols such as NNTP and POP3 produce messages of this type. + *

+ * This class handles stripping of the duplicate period at the beginning + * of lines starting with a period, converts NETASCII newlines to the + * local line separator format, truncates the end of message indicator, + * and ensures you cannot read past the end of the message. + * @author Daniel F. Savarese + * @version $Id: DotTerminatedMessageReader.java 636825 2008-03-13 18:34:52Z sebb $ + */ +public final class DotTerminatedMessageReader extends Reader +{ + private static final String LS; + private static final char[] LS_CHARS; + + static + { + LS = System.getProperty("line.separator"); + LS_CHARS = LS.toCharArray(); + } + + private boolean atBeginning; + private boolean eof; + private int pos; + private char[] internalBuffer; + private PushbackReader internalReader; + + /** + * Creates a DotTerminatedMessageReader that wraps an existing Reader + * input source. + * @param reader The Reader input source containing the message. + */ + public DotTerminatedMessageReader(Reader reader) + { + super(reader); + internalBuffer = new char[LS_CHARS.length + 3]; + pos = internalBuffer.length; + // Assumes input is at start of message + atBeginning = true; + eof = false; + internalReader = new PushbackReader(reader); + } + + /** + * Reads and returns the next character in the message. If the end of the + * message has been reached, returns -1. Note that a call to this method + * may result in multiple reads from the underlying input stream to decode + * the message properly (removing doubled dots and so on). All of + * this is transparent to the programmer and is only mentioned for + * completeness. + * @return The next character in the message. Returns -1 if the end of the + * message has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + */ + @Override + public int read() throws IOException + { + int ch; + + synchronized (lock) + { + if (pos < internalBuffer.length) + { + return internalBuffer[pos++]; + } + + if (eof) + { + return -1; + } + + if ((ch = internalReader.read()) == -1) + { + eof = true; + return -1; + } + + if (atBeginning) + { + atBeginning = false; + if (ch == '.') + { + ch = internalReader.read(); + + if (ch != '.') + { + // read newline + eof = true; + internalReader.read(); + return -1; + } + else + { + return '.'; + } + } + } + + if (ch == '\r') + { + ch = internalReader.read(); + + if (ch == '\n') + { + ch = internalReader.read(); + + if (ch == '.') + { + ch = internalReader.read(); + + if (ch != '.') + { + // read newline and indicate end of file + internalReader.read(); + eof = true; + } + else + { + internalBuffer[--pos] = (char) ch; + } + } + else + { + internalReader.unread(ch); + } + + pos -= LS_CHARS.length; + System.arraycopy(LS_CHARS, 0, internalBuffer, pos, + LS_CHARS.length); + ch = internalBuffer[pos++]; + } + else + { + internalBuffer[--pos] = (char) ch; + return '\r'; + } + } + + return ch; + } + } + + /** + * Reads the next characters from the message into an array and + * returns the number of characters read. Returns -1 if the end of the + * message has been reached. + * @param buffer The character array in which to store the characters. + * @return The number of characters read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + */ + @Override + public int read(char[] buffer) throws IOException + { + return read(buffer, 0, buffer.length); + } + + /** + * Reads the next characters from the message into an array and + * returns the number of characters read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + * @param buffer The character array in which to store the characters. + * @param offset The offset into the array at which to start storing + * characters. + * @param length The number of characters to read. + * @return The number of characters read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + */ + @Override + public int read(char[] buffer, int offset, int length) throws IOException + { + int ch, off; + synchronized (lock) + { + if (length < 1) + { + return 0; + } + if ((ch = read()) == -1) + { + return -1; + } + off = offset; + + do + { + buffer[offset++] = (char) ch; + } + while (--length > 0 && (ch = read()) != -1); + + return (offset - off); + } + } + + /** + * Determines if the message is ready to be read. + * @return True if the message is ready to be read, false if not. + * @exception IOException If an error occurs while checking the underlying + * stream. + */ + @Override + public boolean ready() throws IOException + { + synchronized (lock) + { + return (pos < internalBuffer.length || internalReader.ready()); + } + } + + /** + * Closes the message for reading. This doesn't actually close the + * underlying stream. The underlying stream may still be used for + * communicating with the server and therefore is not closed. + *

+ * If the end of the message has not yet been reached, this method + * will read the remainder of the message until it reaches the end, + * so that the underlying stream may continue to be used properly + * for communicating with the server. If you do not fully read + * a message, you MUST close it, otherwise your program will likely + * hang or behave improperly. + * @exception IOException If an error occurs while reading the + * underlying stream. + */ + @Override + public void close() throws IOException + { + synchronized (lock) + { + if (internalReader == null) + { + return; + } + + if (!eof) + { + while (read() != -1) + { + ; + } + } + eof = true; + atBeginning = false; + pos = internalBuffer.length; + internalReader = null; + } + } +} diff --git a/org/apache/commons/net/io/DotTerminatedMessageWriter.java b/org/apache/commons/net/io/DotTerminatedMessageWriter.java new file mode 100644 index 0000000..853e42f --- /dev/null +++ b/org/apache/commons/net/io/DotTerminatedMessageWriter.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.Writer; + +/*** + * DotTerminatedMessageWriter is a class used to write messages to a + * server that are terminated by a single dot followed by a + * <CR><LF> + * sequence and with double dots appearing at the begining of lines which + * do not signal end of message yet start with a dot. Various Internet + * protocols such as NNTP and POP3 produce messages of this type. + *

+ * This class handles the doubling of line-starting periods, + * converts single linefeeds to NETASCII newlines, and on closing + * will send the final message terminator dot and NETASCII newline + * sequence. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class DotTerminatedMessageWriter extends Writer +{ + private static final int __NOTHING_SPECIAL_STATE = 0; + private static final int __LAST_WAS_CR_STATE = 1; + private static final int __LAST_WAS_NL_STATE = 2; + + private int __state; + private Writer __output; + + + /*** + * Creates a DotTerminatedMessageWriter that wraps an existing Writer + * output destination. + *

+ * @param output The Writer output destination to write the message. + ***/ + public DotTerminatedMessageWriter(Writer output) + { + super(output); + __output = output; + __state = __NOTHING_SPECIAL_STATE; + } + + + /*** + * Writes a character to the output. Note that a call to this method + * may result in multiple writes to the underling Writer in order to + * convert naked linefeeds to NETASCII line separators and to double + * line-leading periods. This is transparent to the programmer and + * is only mentioned for completeness. + *

+ * @param ch The character to write. + * @exception IOException If an error occurs while writing to the + * underlying output. + ***/ + @Override + public void write(int ch) throws IOException + { + synchronized (lock) + { + switch (ch) + { + case '\r': + __state = __LAST_WAS_CR_STATE; + __output.write('\r'); + return ; + case '\n': + if (__state != __LAST_WAS_CR_STATE) + __output.write('\r'); + __output.write('\n'); + __state = __LAST_WAS_NL_STATE; + return ; + case '.': + // Double the dot at the beginning of a line + if (__state == __LAST_WAS_NL_STATE) + __output.write('.'); + // Fall through + default: + __state = __NOTHING_SPECIAL_STATE; + __output.write(ch); + return ; + } + } + } + + + /*** + * Writes a number of characters from a character array to the output + * starting from a given offset. + *

+ * @param buffer The character array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of characters to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(char[] buffer, int offset, int length) throws IOException + { + synchronized (lock) + { + while (length-- > 0) + write(buffer[offset++]); + } + } + + + /*** + * Writes a character array to the output. + *

+ * @param buffer The character array to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(char[] buffer) throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a String to the output. + *

+ * @param string The String to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(String string) throws IOException + { + write(string.toCharArray()); + } + + + /*** + * Writes part of a String to the output starting from a given offset. + *

+ * @param string The String to write. + * @param offset The offset into the String at which to start copying data. + * @param length The number of characters to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(String string, int offset, int length) throws IOException + { + write(string.toCharArray(), offset, length); + } + + + /*** + * Flushes the underlying output, writing all buffered output. + *

+ * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void flush() throws IOException + { + synchronized (lock) + { + __output.flush(); + } + } + + + /*** + * Flushes the underlying output, writing all buffered output, but doesn't + * actually close the underlying stream. The underlying stream may still + * be used for communicating with the server and therefore is not closed. + *

+ * @exception IOException If an error occurs while writing to the underlying + * output or closing the Writer. + ***/ + @Override + public void close() throws IOException + { + synchronized (lock) + { + if (__output == null) + return ; + + if (__state == __LAST_WAS_CR_STATE) + __output.write('\n'); + else if (__state != __LAST_WAS_NL_STATE) + __output.write("\r\n"); + + __output.write(".\r\n"); + + __output.flush(); + __output = null; + } + } + +} diff --git a/org/apache/commons/net/io/FromNetASCIIInputStream.class b/org/apache/commons/net/io/FromNetASCIIInputStream.class new file mode 100644 index 0000000..d3bf9c1 Binary files /dev/null and b/org/apache/commons/net/io/FromNetASCIIInputStream.class differ diff --git a/org/apache/commons/net/io/FromNetASCIIInputStream.java b/org/apache/commons/net/io/FromNetASCIIInputStream.java new file mode 100644 index 0000000..76588ab --- /dev/null +++ b/org/apache/commons/net/io/FromNetASCIIInputStream.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + +/*** + * This class wraps an input stream, replacing all occurrences + * of <CR><LF> (carriage return followed by a linefeed), + * which is the NETASCII standard for representing a newline, with the + * local line separator representation. You would use this class to + * implement ASCII file transfers requiring conversion from NETASCII. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FromNetASCIIInputStream extends PushbackInputStream +{ + static final boolean _noConversionRequired; + static final String _lineSeparator; + static final byte[] _lineSeparatorBytes; + + static { + _lineSeparator = System.getProperty("line.separator"); + _noConversionRequired = _lineSeparator.equals("\r\n"); + _lineSeparatorBytes = _lineSeparator.getBytes(); + } + + private int __length = 0; + + /*** + * Returns true if the NetASCII line separator differs from the system + * line separator, false if they are the same. This method is useful + * to determine whether or not you need to instantiate a + * FromNetASCIIInputStream object. + *

+ * @return True if the NETASCII line separator differs from the local + * system line separator, false if they are the same. + ***/ + public static final boolean isConversionRequired() + { + return !_noConversionRequired; + } + + /*** + * Creates a FromNetASCIIInputStream instance that wraps an existing + * InputStream. + ***/ + public FromNetASCIIInputStream(InputStream input) + { + super(input, _lineSeparatorBytes.length + 1); + } + + + private int __read() throws IOException + { + int ch; + + ch = super.read(); + + if (ch == '\r') + { + ch = super.read(); + if (ch == '\n') + { + unread(_lineSeparatorBytes); + ch = super.read(); + // This is a kluge for read(byte[], ...) to read the right amount + --__length; + } + else + { + if (ch != -1) + unread(ch); + return '\r'; + } + } + + return ch; + } + + + /*** + * Reads and returns the next byte in the stream. If the end of the + * message has been reached, returns -1. Note that a call to this method + * may result in multiple reads from the underlying input stream in order + * to convert NETASCII line separators to the local line separator format. + * This is transparent to the programmer and is only mentioned for + * completeness. + *

+ * @return The next character in the stream. Returns -1 if the end of the + * stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read() throws IOException + { + if (_noConversionRequired) + return super.read(); + + return __read(); + } + + + /*** + * Reads the next number of bytes from the stream into an array and + * returns the number of bytes read. Returns -1 if the end of the + * stream has been reached. + *

+ * @param buffer The byte array in which to store the data. + * @return The number of bytes read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[]) throws IOException + { + return read(buffer, 0, buffer.length); + } + + + /*** + * Reads the next number of bytes from the stream into an array and returns + * the number of bytes read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + *

+ * @param buffer The byte array in which to store the data. + * @param offset The offset into the array at which to start storing data. + * @param length The number of bytes to read. + * @return The number of bytes read. Returns -1 if the + * end of the stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[], int offset, int length) throws IOException + { + int ch, off; + + if (length < 1) + return 0; + + ch = available(); + + __length = (length > ch ? ch : length); + + // If nothing is available, block to read only one character + if (__length < 1) + __length = 1; + + if (_noConversionRequired) + return super.read(buffer, offset, __length); + + if ((ch = __read()) == -1) + return -1; + + off = offset; + + do + { + buffer[offset++] = (byte)ch; + } + while (--__length > 0 && (ch = __read()) != -1); + + + return (offset - off); + } + + + // PushbackInputStream in JDK 1.1.3 returns the wrong thing + /*** + * Returns the number of bytes that can be read without blocking EXCEPT + * when newline conversions have to be made somewhere within the + * available block of bytes. In other words, you really should not + * rely on the value returned by this method if you are trying to avoid + * blocking. + ***/ + @Override + public int available() throws IOException + { + return (buf.length - pos) + in.available(); + } + +} diff --git a/org/apache/commons/net/io/FromNetASCIIOutputStream.java b/org/apache/commons/net/io/FromNetASCIIOutputStream.java new file mode 100644 index 0000000..c025a1b --- /dev/null +++ b/org/apache/commons/net/io/FromNetASCIIOutputStream.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/*** + * This class wraps an output stream, replacing all occurrences + * of <CR><LF> (carriage return followed by a linefeed), + * which is the NETASCII standard for representing a newline, with the + * local line separator representation. You would use this class to + * implement ASCII file transfers requiring conversion from NETASCII. + *

+ * Because of the translation process, a call to flush() will + * not flush the last byte written if that byte was a carriage + * return. A call to {@link #close close() }, however, will + * flush the carriage return. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FromNetASCIIOutputStream extends FilterOutputStream +{ + private boolean __lastWasCR; + + /*** + * Creates a FromNetASCIIOutputStream instance that wraps an existing + * OutputStream. + *

+ * @param output The OutputStream to wrap. + ***/ + public FromNetASCIIOutputStream(OutputStream output) + { + super(output); + __lastWasCR = false; + } + + + private void __write(int ch) throws IOException + { + switch (ch) + { + case '\r': + __lastWasCR = true; + // Don't write anything. We need to see if next one is linefeed + break; + case '\n': + if (__lastWasCR) + { + out.write(FromNetASCIIInputStream._lineSeparatorBytes); + __lastWasCR = false; + break; + } + __lastWasCR = false; + out.write('\n'); + break; + default: + if (__lastWasCR) + { + out.write('\r'); + __lastWasCR = false; + } + out.write(ch); + break; + } + } + + + /*** + * Writes a byte to the stream. Note that a call to this method + * might not actually write a byte to the underlying stream until a + * subsequent character is written, from which it can be determined if + * a NETASCII line separator was encountered. + * This is transparent to the programmer and is only mentioned for + * completeness. + *

+ * @param ch The byte to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(int ch) + throws IOException + { + if (FromNetASCIIInputStream._noConversionRequired) + { + out.write(ch); + return ; + } + + __write(ch); + } + + + /*** + * Writes a byte array to the stream. + *

+ * @param buffer The byte array to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[]) + throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[], int offset, int length) + throws IOException + { + if (FromNetASCIIInputStream._noConversionRequired) + { + // FilterOutputStream method is very slow. + //super.write(buffer, offset, length); + out.write(buffer, offset, length); + return ; + } + + while (length-- > 0) + __write(buffer[offset++]); + } + + + /*** + * Closes the stream, writing all pending data. + *

+ * @exception IOException If an error occurs while closing the stream. + ***/ + @Override + public synchronized void close() + throws IOException + { + if (FromNetASCIIInputStream._noConversionRequired) + { + super.close(); + return ; + } + + if (__lastWasCR) + out.write('\r'); + super.close(); + } +} diff --git a/org/apache/commons/net/io/SocketInputStream.class b/org/apache/commons/net/io/SocketInputStream.class new file mode 100644 index 0000000..97657e8 Binary files /dev/null and b/org/apache/commons/net/io/SocketInputStream.class differ diff --git a/org/apache/commons/net/io/SocketInputStream.java b/org/apache/commons/net/io/SocketInputStream.java new file mode 100644 index 0000000..673f434 --- /dev/null +++ b/org/apache/commons/net/io/SocketInputStream.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; + +/*** + * This class wraps an input stream, storing a reference to its originating + * socket. When the stream is closed, it will also close the socket + * immediately afterward. This class is useful for situations where you + * are dealing with a stream originating from a socket, but do not have + * a reference to the socket, and want to make sure it closes when the + * stream closes. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketOutputStream + ***/ + +public class SocketInputStream extends FilterInputStream +{ + private Socket __socket; + + /*** + * Creates a SocketInputStream instance wrapping an input stream and + * storing a reference to a socket that should be closed on closing + * the stream. + *

+ * @param socket The socket to close on closing the stream. + * @param stream The input stream to wrap. + ***/ + public SocketInputStream(Socket socket, InputStream stream) + { + super(stream); + __socket = socket; + } + + /*** + * Closes the stream and immediately afterward closes the referenced + * socket. + *

+ * @exception IOException If there is an error in closing the stream + * or socket. + ***/ + @Override + public void close() throws IOException + { + super.close(); + __socket.close(); + } +} diff --git a/org/apache/commons/net/io/SocketOutputStream.class b/org/apache/commons/net/io/SocketOutputStream.class new file mode 100644 index 0000000..41a30e5 Binary files /dev/null and b/org/apache/commons/net/io/SocketOutputStream.class differ diff --git a/org/apache/commons/net/io/SocketOutputStream.java b/org/apache/commons/net/io/SocketOutputStream.java new file mode 100644 index 0000000..abd7f5d --- /dev/null +++ b/org/apache/commons/net/io/SocketOutputStream.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/*** + * This class wraps an output stream, storing a reference to its originating + * socket. When the stream is closed, it will also close the socket + * immediately afterward. This class is useful for situations where you + * are dealing with a stream originating from a socket, but do not have + * a reference to the socket, and want to make sure it closes when the + * stream closes. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketInputStream + ***/ + +public class SocketOutputStream extends FilterOutputStream +{ + private Socket __socket; + + /*** + * Creates a SocketOutputStream instance wrapping an output stream and + * storing a reference to a socket that should be closed on closing + * the stream. + *

+ * @param socket The socket to close on closing the stream. + * @param stream The input stream to wrap. + ***/ + public SocketOutputStream(Socket socket, OutputStream stream) + { + super(stream); + __socket = socket; + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. This method bypasses the equivalent method in + * FilterOutputStream because the FilterOutputStream implementation is + * very inefficient. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(byte buffer[], int offset, int length) throws IOException + { + out.write(buffer, offset, length); + } + + + /*** + * Closes the stream and immediately afterward closes the referenced + * socket. + *

+ * @exception IOException If there is an error in closing the stream + * or socket. + ***/ + @Override + public void close() throws IOException + { + super.close(); + __socket.close(); + } +} diff --git a/org/apache/commons/net/io/ToNetASCIIInputStream.java b/org/apache/commons/net/io/ToNetASCIIInputStream.java new file mode 100644 index 0000000..55e4735 --- /dev/null +++ b/org/apache/commons/net/io/ToNetASCIIInputStream.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/*** + * This class wraps an input stream, replacing all singly occurring + * <LF> (linefeed) characters with <CR><LF> (carriage return + * followed by linefeed), which is the NETASCII standard for representing + * a newline. + * You would use this class to implement ASCII file transfers requiring + * conversion to NETASCII. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class ToNetASCIIInputStream extends FilterInputStream +{ + private static final int __NOTHING_SPECIAL = 0; + private static final int __LAST_WAS_CR = 1; + private static final int __LAST_WAS_NL = 2; + private int __status; + + /*** + * Creates a ToNetASCIIInputStream instance that wraps an existing + * InputStream. + *

+ * @param input The InputStream to . + ***/ + public ToNetASCIIInputStream(InputStream input) + { + super(input); + __status = __NOTHING_SPECIAL; + } + + + /*** + * Reads and returns the next byte in the stream. If the end of the + * message has been reached, returns -1. + *

+ * @return The next character in the stream. Returns -1 if the end of the + * stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read() throws IOException + { + int ch; + + if (__status == __LAST_WAS_NL) + { + __status = __NOTHING_SPECIAL; + return '\n'; + } + + ch = in.read(); + + switch (ch) + { + case '\r': + __status = __LAST_WAS_CR; + return '\r'; + case '\n': + if (__status != __LAST_WAS_CR) + { + __status = __LAST_WAS_NL; + return '\r'; + } + // else fall through + default: + __status = __NOTHING_SPECIAL; + return ch; + } + // statement not reached + //return ch; + } + + + /*** + * Reads the next number of bytes from the stream into an array and + * returns the number of bytes read. Returns -1 if the end of the + * stream has been reached. + *

+ * @param buffer The byte array in which to store the data. + * @return The number of bytes read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[]) throws IOException + { + return read(buffer, 0, buffer.length); + } + + + /*** + * Reads the next number of bytes from the stream into an array and returns + * the number of bytes read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + *

+ * @param buffer The byte array in which to store the data. + * @param offset The offset into the array at which to start storing data. + * @param length The number of bytes to read. + * @return The number of bytes read. Returns -1 if the + * end of the stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[], int offset, int length) throws IOException + { + int ch, off; + + if (length < 1) + return 0; + + ch = available(); + + if (length > ch) + length = ch; + + // If nothing is available, block to read only one character + if (length < 1) + length = 1; + + if ((ch = read()) == -1) + return -1; + + off = offset; + + do + { + buffer[offset++] = (byte)ch; + } + while (--length > 0 && (ch = read()) != -1); + + return (offset - off); + } + + /*** Returns false. Mark is not supported. ***/ + @Override + public boolean markSupported() + { + return false; + } + + @Override + public int available() throws IOException + { + int result; + + result = in.available(); + + if (__status == __LAST_WAS_NL) + return (result + 1); + + return result; + } +} diff --git a/org/apache/commons/net/io/ToNetASCIIOutputStream.class b/org/apache/commons/net/io/ToNetASCIIOutputStream.class new file mode 100644 index 0000000..62185e4 Binary files /dev/null and b/org/apache/commons/net/io/ToNetASCIIOutputStream.class differ diff --git a/org/apache/commons/net/io/ToNetASCIIOutputStream.java b/org/apache/commons/net/io/ToNetASCIIOutputStream.java new file mode 100644 index 0000000..aeacc98 --- /dev/null +++ b/org/apache/commons/net/io/ToNetASCIIOutputStream.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/*** + * This class wraps an output stream, replacing all singly occurring + * <LF> (linefeed) characters with <CR><LF> (carriage return + * followed by linefeed), which is the NETASCII standard for representing + * a newline. + * You would use this class to implement ASCII file transfers requiring + * conversion to NETASCII. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class ToNetASCIIOutputStream extends FilterOutputStream +{ + private boolean __lastWasCR; + + /*** + * Creates a ToNetASCIIOutputStream instance that wraps an existing + * OutputStream. + *

+ * @param output The OutputStream to wrap. + ***/ + public ToNetASCIIOutputStream(OutputStream output) + { + super(output); + __lastWasCR = false; + } + + + /*** + * Writes a byte to the stream. Note that a call to this method + * may result in multiple writes to the underlying input stream in order + * to convert naked newlines to NETASCII line separators. + * This is transparent to the programmer and is only mentioned for + * completeness. + *

+ * @param ch The byte to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(int ch) + throws IOException + { + switch (ch) + { + case '\r': + __lastWasCR = true; + out.write('\r'); + return ; + case '\n': + if (!__lastWasCR) + out.write('\r'); + // Fall through + default: + __lastWasCR = false; + out.write(ch); + return ; + } + } + + + /*** + * Writes a byte array to the stream. + *

+ * @param buffer The byte array to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[]) + throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[], int offset, int length) + throws IOException + { + while (length-- > 0) + write(buffer[offset++]); + } + +} diff --git a/org/apache/commons/net/io/Util.class b/org/apache/commons/net/io/Util.class new file mode 100644 index 0000000..7509801 Binary files /dev/null and b/org/apache/commons/net/io/Util.class differ diff --git a/org/apache/commons/net/io/Util.java b/org/apache/commons/net/io/Util.java new file mode 100644 index 0000000..4e85a93 --- /dev/null +++ b/org/apache/commons/net/io/Util.java @@ -0,0 +1,334 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/*** + * The Util class cannot be instantiated and stores short static convenience + * methods that are often quite useful. + *

+ *

+ * @see CopyStreamException + * @see CopyStreamListener + * @see CopyStreamAdapter + * @author Daniel F. Savarese + ***/ + +public final class Util +{ + /*** + * The default buffer size used by {@link #copyStream copyStream } + * and {@link #copyReader copyReader }. It's value is 1024. + ***/ + public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; + + // Cannot be instantiated + private Util() + { } + + + /*** + * Copies the contents of an InputStream to an OutputStream using a + * copy buffer of a given size and notifies the provided + * CopyStreamListener of the progress of the copy operation by calling + * its bytesTransferred(long, int) method after each write to the + * destination. If you wish to notify more than one listener you should + * use a CopyStreamAdapter as the listener and register the additional + * listeners with the CopyStreamAdapter. + *

+ * The contents of the InputStream are + * read until the end of the stream is reached, but neither the + * source nor the destination are closed. You must do this yourself + * outside of the method call. The number of bytes read/written is + * returned. + *

+ * @param source The source InputStream. + * @param dest The destination OutputStream. + * @param bufferSize The number of bytes to buffer during the copy. + * @param streamSize The number of bytes in the stream being copied. + * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. + * @param listener The CopyStreamListener to notify of progress. If + * this parameter is null, notification is not attempted. + * @param flush Whether to flush the output stream after every + * write. This is necessary for interactive sessions that rely on + * buffered streams. If you don't flush, the data will stay in + * the stream buffer. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyStream(InputStream source, OutputStream dest, + int bufferSize, long streamSize, + CopyStreamListener listener, + boolean flush) + throws CopyStreamException + { + int bytes; + long total; + byte[] buffer; + + buffer = new byte[bufferSize]; + total = 0; + + try + { + while ((bytes = source.read(buffer)) != -1) + { + // Technically, some read(byte[]) methods may return 0 and we cannot + // accept that as an indication of EOF. + + if (bytes == 0) + { + bytes = source.read(); + if (bytes < 0) + break; + dest.write(bytes); + if(flush) + dest.flush(); + ++total; + if (listener != null) + listener.bytesTransferred(total, 1, streamSize); + continue; + } + + dest.write(buffer, 0, bytes); + if(flush) + dest.flush(); + total += bytes; + if (listener != null) + listener.bytesTransferred(total, bytes, streamSize); + } + } + catch (IOException e) + { + throw new CopyStreamException("IOException caught while copying.", + total, e); + } + + return total; + } + + + /*** + * Copies the contents of an InputStream to an OutputStream using a + * copy buffer of a given size and notifies the provided + * CopyStreamListener of the progress of the copy operation by calling + * its bytesTransferred(long, int) method after each write to the + * destination. If you wish to notify more than one listener you should + * use a CopyStreamAdapter as the listener and register the additional + * listeners with the CopyStreamAdapter. + *

+ * The contents of the InputStream are + * read until the end of the stream is reached, but neither the + * source nor the destination are closed. You must do this yourself + * outside of the method call. The number of bytes read/written is + * returned. + *

+ * @param source The source InputStream. + * @param dest The destination OutputStream. + * @param bufferSize The number of bytes to buffer during the copy. + * @param streamSize The number of bytes in the stream being copied. + * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. + * @param listener The CopyStreamListener to notify of progress. If + * this parameter is null, notification is not attempted. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyStream(InputStream source, OutputStream dest, + int bufferSize, long streamSize, + CopyStreamListener listener) + throws CopyStreamException + { + return copyStream(source, dest, bufferSize, streamSize, listener, + true); + } + + + /*** + * Copies the contents of an InputStream to an OutputStream using a + * copy buffer of a given size. The contents of the InputStream are + * read until the end of the stream is reached, but neither the + * source nor the destination are closed. You must do this yourself + * outside of the method call. The number of bytes read/written is + * returned. + *

+ * @param source The source InputStream. + * @param dest The destination OutputStream. + * @return The number of bytes read/written in the copy operation. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyStream(InputStream source, OutputStream dest, + int bufferSize) + throws CopyStreamException + { + return copyStream(source, dest, bufferSize, + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); + } + + + /*** + * Same as copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); + ***/ + public static final long copyStream(InputStream source, OutputStream dest) + throws CopyStreamException + { + return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); + } + + + /*** + * Copies the contents of a Reader to a Writer using a + * copy buffer of a given size and notifies the provided + * CopyStreamListener of the progress of the copy operation by calling + * its bytesTransferred(long, int) method after each write to the + * destination. If you wish to notify more than one listener you should + * use a CopyStreamAdapter as the listener and register the additional + * listeners with the CopyStreamAdapter. + *

+ * The contents of the Reader are + * read until its end is reached, but neither the source nor the + * destination are closed. You must do this yourself outside of the + * method call. The number of characters read/written is returned. + *

+ * @param source The source Reader. + * @param dest The destination writer. + * @param bufferSize The number of characters to buffer during the copy. + * @param streamSize The number of characters in the stream being copied. + * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. + * @param listener The CopyStreamListener to notify of progress. If + * this parameter is null, notification is not attempted. + * @return The number of characters read/written in the copy operation. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyReader(Reader source, Writer dest, + int bufferSize, long streamSize, + CopyStreamListener listener) + throws CopyStreamException + { + int chars; + long total; + char[] buffer; + + buffer = new char[bufferSize]; + total = 0; + + try + { + while ((chars = source.read(buffer)) != -1) + { + // Technically, some read(char[]) methods may return 0 and we cannot + // accept that as an indication of EOF. + if (chars == 0) + { + chars = source.read(); + if (chars < 0) + break; + dest.write(chars); + dest.flush(); + ++total; + if (listener != null) + listener.bytesTransferred(total, chars, streamSize); + continue; + } + + dest.write(buffer, 0, chars); + dest.flush(); + total += chars; + if (listener != null) + listener.bytesTransferred(total, chars, streamSize); + } + } + catch (IOException e) + { + throw new CopyStreamException("IOException caught while copying.", + total, e); + } + + return total; + } + + + /*** + * Copies the contents of a Reader to a Writer using a + * copy buffer of a given size. The contents of the Reader are + * read until its end is reached, but neither the source nor the + * destination are closed. You must do this yourself outside of the + * method call. The number of characters read/written is returned. + *

+ * @param source The source Reader. + * @param dest The destination writer. + * @param bufferSize The number of characters to buffer during the copy. + * @return The number of characters read/written in the copy operation. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyReader(Reader source, Writer dest, + int bufferSize) + throws CopyStreamException + { + return copyReader(source, dest, bufferSize, + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); + } + + + /*** + * Same as copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); + ***/ + public static final long copyReader(Reader source, Writer dest) + throws CopyStreamException + { + return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); + } + +} diff --git a/org/apache/commons/net/nntp/Article.java b/org/apache/commons/net/nntp/Article.java new file mode 100644 index 0000000..cccba3b --- /dev/null +++ b/org/apache/commons/net/nntp/Article.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +import java.util.ArrayList; +import java.util.StringTokenizer; + +/** + * This is a class that contains the basic state needed for message retrieval and threading. + * With thanks to Jamie Zawinski + * @author rwinston + * + */ +public class Article implements Threadable { + private int articleNumber; + private String subject; + private String date; + private String articleId; + private String simplifiedSubject; + private String from; + private StringBuffer header; + private StringBuffer references; + private boolean isReply = false; + + public Article kid, next; + + public Article() { + header = new StringBuffer(); + } + + /** + * Adds an arbitrary header key and value to this message's header. + * @param name the header name + * @param val the header value + */ + public void addHeaderField(String name, String val) { + header.append(name); + header.append(": "); + header.append(val); + header.append('\n'); + } + + /** + * Adds a message-id to the list of messages that this message references (i.e. replies to) + * @param msgId + */ + public void addReference(String msgId) { + if (references == null) { + references = new StringBuffer(); + references.append("References: "); + } + references.append(msgId); + references.append("\t"); + } + + /** + * Returns the MessageId references as an array of Strings + * @return an array of message-ids + */ + public String[] getReferences() { + if (references == null) + return new String[0]; + ArrayList list = new ArrayList(); + int terminator = references.toString().indexOf(':'); + StringTokenizer st = + new StringTokenizer(references.substring(terminator), "\t"); + while (st.hasMoreTokens()) { + list.add(st.nextToken()); + } + return list.toArray(new String[list.size()]); + } + + /** + * Attempts to parse the subject line for some typical reply signatures, and strip them out + * + */ + private void simplifySubject() { + int start = 0; + String subject = getSubject(); + int len = subject.length(); + + boolean done = false; + + while (!done) { + done = true; + + // skip whitespace + // "Re: " breaks this + while (start < len && subject.charAt(start) == ' ') { + start++; + } + + if (start < (len - 2) + && (subject.charAt(start) == 'r' || subject.charAt(start) == 'R') + && (subject.charAt(start + 1) == 'e' || subject.charAt(start + 1) == 'E')) { + + if (subject.charAt(start + 2) == ':') { + start += 3; // Skip "Re:" + isReply = true; + done = false; + } else if ( + start < (len - 2) + && + (subject.charAt(start + 2) == '[' || subject.charAt(start + 2) == '(')) { + + int i = start + 3; + + while (i < len && subject.charAt(i) >= '0' && subject.charAt(i) <= '9') + i++; + + if (i < (len - 1) + && (subject.charAt(i) == ']' || subject.charAt(i) == ')') + && subject.charAt(i + 1) == ':') { + start = i + 2; + isReply = true; + done = false; + } + } + } + + if (simplifiedSubject == "(no subject)") + simplifiedSubject = ""; + + int end = len; + + while (end > start && subject.charAt(end - 1) < ' ') + end--; + + if (start == 0 && end == len) + simplifiedSubject = subject; + else + simplifiedSubject = subject.substring(start, end); + } + } + + /** + * Recursive method that traverses a pre-threaded graph (or tree) + * of connected Article objects and prints them out. + * @param article the root of the article 'tree' + * @param depth the current tree depth + */ + public static void printThread(Article article, int depth) { + for (int i = 0; i < depth; ++i) + System.out.print("==>"); + System.out.println(article.getSubject() + "\t" + article.getFrom()); + if (article.kid != null) + printThread(article.kid, depth + 1); + if (article.next != null) + printThread(article.next, depth); + } + + public String getArticleId() { + return articleId; + } + + public int getArticleNumber() { + return articleNumber; + } + + public String getDate() { + return date; + } + + public String getFrom() { + return from; + } + + public String getSubject() { + return subject; + } + + public void setArticleId(String string) { + articleId = string; + } + + public void setArticleNumber(int i) { + articleNumber = i; + } + + public void setDate(String string) { + date = string; + } + + public void setFrom(String string) { + from = string; + } + + public void setSubject(String string) { + subject = string; + } + + + public boolean isDummy() { + return (getSubject() == null); + } + + public String messageThreadId() { + return articleId; + } + + public String[] messageThreadReferences() { + return getReferences(); + } + + public String simplifiedSubject() { + if(simplifiedSubject == null) + simplifySubject(); + return simplifiedSubject; + } + + + public boolean subjectIsReply() { + if(simplifiedSubject == null) + simplifySubject(); + return isReply; + } + + + public void setChild(Threadable child) { + this.kid = (Article) child; + flushSubjectCache(); + } + + private void flushSubjectCache() { + simplifiedSubject = null; + } + + + public void setNext(Threadable next) { + this.next = (Article)next; + flushSubjectCache(); + } + + + public Threadable makeDummy() { + return new Article(); + } +} diff --git a/org/apache/commons/net/nntp/ArticlePointer.java b/org/apache/commons/net/nntp/ArticlePointer.java new file mode 100644 index 0000000..a810cad --- /dev/null +++ b/org/apache/commons/net/nntp/ArticlePointer.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +/** + * This class is a structure used to return article number and unique + * id information extracted from an NNTP server reply. You will normally + * want this information when issuing a STAT command, implemented by + * {@link NNTPClient#selectArticle selectArticle}. + * @author Daniel F. Savarese + * @see NNTPClient + */ +public final class ArticlePointer +{ + /** The number of the referenced article. */ + public int articleNumber; + /** + * The unique id of the referenced article, including the enclosing + * < and > symbols which are technically not part of the + * identifier, but are required by all NNTP commands taking an + * article id as an argument. + */ + public String articleId; +} diff --git a/org/apache/commons/net/nntp/NNTP.java b/org/apache/commons/net/nntp/NNTP.java new file mode 100644 index 0000000..225e064 --- /dev/null +++ b/org/apache/commons/net/nntp/NNTP.java @@ -0,0 +1,1022 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ProtocolCommandListener; +import org.apache.commons.net.ProtocolCommandSupport; +import org.apache.commons.net.SocketClient; + +/*** + * The NNTP class is not meant to be used by itself and is provided + * only so that you may easily implement your own NNTP client if + * you so desire. If you have no need to perform your own implementation, + * you should use {@link org.apache.commons.net.nntp.NNTPClient}. + * The NNTP class is made public to provide access to various NNTP constants + * and to make it easier for adventurous programmers (or those with special + * needs) to interact with the NNTP protocol and implement their own clients. + * A set of methods with names corresponding to the NNTP command names are + * provided to facilitate this interaction. + *

+ * You should keep in mind that the NNTP server may choose to prematurely + * close a connection if the client has been idle for longer than a + * given time period or if the server is being shutdown by the operator or + * some other reason. The NNTP class will detect a + * premature NNTP server connection closing when it receives a + * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } + * response to a command. + * When that occurs, the NNTP class method encountering that reply will throw + * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} + * . + * NNTPConectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} + * , you must disconnect the connection with + * {@link #disconnect disconnect() } to properly clean up the + * system resources used by NNTP. Before disconnecting, you may check the + * last reply code and text with + * {@link #getReplyCode getReplyCode } and + * {@link #getReplyString getReplyString }. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @author Ted Wise + * @see NNTPClient + * @see NNTPConnectionClosedException + * @see org.apache.commons.net.MalformedServerReplyException + ***/ + +public class NNTP extends SocketClient +{ + /*** The default NNTP port. Its value is 119 according to RFC 977. ***/ + public static final int DEFAULT_PORT = 119; + + // We have to ensure that the protocol communication is in ASCII + // but we use ISO-8859-1 just in case 8-bit characters cross + // the wire. + private static final String __DEFAULT_ENCODING = "ISO-8859-1"; + + private StringBuffer __commandBuffer; + + boolean _isAllowedToPost; + int _replyCode; + String _replyString; + + /** + * Wraps {@link SocketClient#_input_} + * to communicate with server. Initialized by {@link #_connectAction_}. + * All server reads should be done through this variable. + */ + protected BufferedReader _reader_; + + /** + * Wraps {@link SocketClient#_output_} + * to communicate with server. Initialized by {@link #_connectAction_}. + * All server reads should be done through this variable. + */ + protected BufferedWriter _writer_; + + /*** + * A ProtocolCommandSupport object used to manage the registering of + * ProtocolCommandListeners and te firing of ProtocolCommandEvents. + ***/ + protected ProtocolCommandSupport _commandSupport_; + + /*** + * The default NNTP constructor. Sets the default port to + * DEFAULT_PORT and initializes internal data structures + * for saving NNTP reply information. + ***/ + public NNTP() + { + setDefaultPort(DEFAULT_PORT); + __commandBuffer = new StringBuffer(); + _replyString = null; + _reader_ = null; + _writer_ = null; + _isAllowedToPost = false; + _commandSupport_ = new ProtocolCommandSupport(this); + } + + private void __getReply() throws IOException + { + _replyString = _reader_.readLine(); + + if (_replyString == null) + throw new NNTPConnectionClosedException( + "Connection closed without indication."); + + // In case we run into an anomaly we don't want fatal index exceptions + // to be thrown. + if (_replyString.length() < 3) + throw new MalformedServerReplyException( + "Truncated server reply: " + _replyString); + try + { + _replyCode = Integer.parseInt(_replyString.substring(0, 3)); + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse response code.\nServer Reply: " + _replyString); + } + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireReplyReceived(_replyCode, _replyString + + SocketClient.NETASCII_EOL); + + if (_replyCode == NNTPReply.SERVICE_DISCONTINUED) + throw new NNTPConnectionClosedException( + "NNTP response 400 received. Server closed connection."); + } + + /*** + * Initiates control connections and gets initial reply, determining + * if the client is allowed to post to the server. Initializes + * {@link #_reader_} and {@link #_writer_} to wrap + * {@link SocketClient#_input_} and {@link SocketClient#_output_}. + ***/ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + _reader_ = + new BufferedReader(new InputStreamReader(_input_, + __DEFAULT_ENCODING)); + _writer_ = + new BufferedWriter(new OutputStreamWriter(_output_, + __DEFAULT_ENCODING)); + __getReply(); + + _isAllowedToPost = (_replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED); + } + + /*** + * Adds a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.addProtocolCommandListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.removeProtocolCommandListener(listener); + } + + /*** + * Closes the connection to the NNTP server and sets to null + * some internal data so that the memory may be reclaimed by the + * garbage collector. The reply text and code information from the + * last command is voided so that the memory it used may be reclaimed. + *

+ * @exception IOException If an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + _reader_ = null; + _writer_ = null; + _replyString = null; + _isAllowedToPost = false; + } + + + /*** + * Indicates whether or not the client is allowed to post articles to + * the server it is currently connected to. + *

+ * @return True if the client can post articles to the server, false + * otherwise. + ***/ + public boolean isAllowedToPost() + { + return _isAllowedToPost; + } + + + /*** + * Sends an NNTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString }. + *

+ * @param command The text representation of the NNTP command to send. + * @param args The arguments to the NNTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the NNTP reply code returned by the server + * in response to the command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command, String args) throws IOException + { + String message; + + __commandBuffer.setLength(0); + __commandBuffer.append(command); + + if (args != null) + { + __commandBuffer.append(' '); + __commandBuffer.append(args); + } + __commandBuffer.append(SocketClient.NETASCII_EOL); + + _writer_.write(message = __commandBuffer.toString()); + _writer_.flush(); + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireCommandSent(command, message); + + __getReply(); + return _replyCode; + } + + + /*** + * Sends an NNTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString }. + *

+ * @param command The NNTPCommand constant corresponding to the NNTP command + * to send. + * @param args The arguments to the NNTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the NNTP reply code returned by the server + * in response to the command. + * in response to the command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command, String args) throws IOException + { + return sendCommand(NNTPCommand._commands[command], args); + } + + + /*** + * Sends an NNTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString }. + *

+ * @param command The text representation of the NNTP command to send. + * @return The integer value of the NNTP reply code returned by the server + * in response to the command. + * in response to the command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Sends an NNTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString }. + *

+ * @param command The NNTPCommand constant corresponding to the NNTP command + * to send. + * @return The integer value of the NNTP reply code returned by the server + * in response to the command. + * in response to the command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Returns the integer value of the reply code of the last NNTP reply. + * You will usually only use this method after you connect to the + * NNTP server to check that the connection was successful since + * connect is of type void. + *

+ * @return The integer value of the reply code of the last NNTP reply. + ***/ + public int getReplyCode() + { + return _replyCode; + } + + /*** + * Fetches a reply from the NNTP server and returns the integer reply + * code. After calling this method, the actual reply text can be accessed + * from {@link #getReplyString getReplyString }. Only use this + * method if you are implementing your own NNTP client or if you need to + * fetch a secondary response from the NNTP server. + *

+ * @return The integer value of the reply code of the fetched NNTP reply. + * in response to the command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while + * receiving the server reply. + ***/ + public int getReply() throws IOException + { + __getReply(); + return _replyCode; + } + + + /*** + * Returns the entire text of the last NNTP server response exactly + * as it was received, not including the end of line marker. + *

+ * @return The entire text from the last NNTP response as a String. + ***/ + public String getReplyString() + { + return _replyString; + } + + + /*** + * A convenience method to send the NNTP ARTICLE command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param messageId The message identifier of the requested article, + * including the encapsulating < and > characters. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int article(String messageId) throws IOException + { + return sendCommand(NNTPCommand.ARTICLE, messageId); + } + + /*** + * A convenience method to send the NNTP ARTICLE command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param articleNumber The number of the article to request from the + * currently selected newsgroup. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int article(int articleNumber) throws IOException + { + return sendCommand(NNTPCommand.ARTICLE, Integer.toString(articleNumber)); + } + + /*** + * A convenience method to send the NNTP ARTICLE command to the server, + * receive the initial reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int article() throws IOException + { + return sendCommand(NNTPCommand.ARTICLE); + } + + + + /*** + * A convenience method to send the NNTP BODY command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param messageId The message identifier of the requested article, + * including the encapsulating < and > characters. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int body(String messageId) throws IOException + { + return sendCommand(NNTPCommand.BODY, messageId); + } + + /*** + * A convenience method to send the NNTP BODY command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param articleNumber The number of the article to request from the + * currently selected newsgroup. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int body(int articleNumber) throws IOException + { + return sendCommand(NNTPCommand.BODY, Integer.toString(articleNumber)); + } + + /*** + * A convenience method to send the NNTP BODY command to the server, + * receive the initial reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int body() throws IOException + { + return sendCommand(NNTPCommand.BODY); + } + + + + /*** + * A convenience method to send the NNTP HEAD command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param messageId The message identifier of the requested article, + * including the encapsulating < and > characters. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int head(String messageId) throws IOException + { + return sendCommand(NNTPCommand.HEAD, messageId); + } + + /*** + * A convenience method to send the NNTP HEAD command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param articleNumber The number of the article to request from the + * currently selected newsgroup. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int head(int articleNumber) throws IOException + { + return sendCommand(NNTPCommand.HEAD, Integer.toString(articleNumber)); + } + + /*** + * A convenience method to send the NNTP HEAD command to the server, + * receive the initial reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int head() throws IOException + { + return sendCommand(NNTPCommand.HEAD); + } + + + + /*** + * A convenience method to send the NNTP STAT command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param messageId The message identifier of the requested article, + * including the encapsulating < and > characters. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat(String messageId) throws IOException + { + return sendCommand(NNTPCommand.STAT, messageId); + } + + /*** + * A convenience method to send the NNTP STAT command to the server, + * receive the initial reply, and return the reply code. + *

+ * @param articleNumber The number of the article to request from the + * currently selected newsgroup. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat(int articleNumber) throws IOException + { + return sendCommand(NNTPCommand.STAT, Integer.toString(articleNumber)); + } + + /*** + * A convenience method to send the NNTP STAT command to the server, + * receive the initial reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat() throws IOException + { + return sendCommand(NNTPCommand.STAT); + } + + + /*** + * A convenience method to send the NNTP GROUP command to the server, + * receive the reply, and return the reply code. + *

+ * @param newsgroup The name of the newsgroup to select. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int group(String newsgroup) throws IOException + { + return sendCommand(NNTPCommand.GROUP, newsgroup); + } + + + /*** + * A convenience method to send the NNTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help() throws IOException + { + return sendCommand(NNTPCommand.HELP); + } + + + /*** + * A convenience method to send the NNTP IHAVE command to the server, + * receive the reply, and return the reply code. + *

+ * @param messageId The article identifier, + * including the encapsulating < and > characters. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int ihave(String messageId) throws IOException + { + return sendCommand(NNTPCommand.IHAVE, messageId); + } + + + /*** + * A convenience method to send the NNTP LAST command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int last() throws IOException + { + return sendCommand(NNTPCommand.LAST); + } + + + + /*** + * A convenience method to send the NNTP LIST command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int list() throws IOException + { + return sendCommand(NNTPCommand.LIST); + } + + + + /*** + * A convenience method to send the NNTP NEXT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int next() throws IOException + { + return sendCommand(NNTPCommand.NEXT); + } + + + /*** + * A convenience method to send the NNTP NEWGROUPS command to the server, + * receive the reply, and return the reply code. + *

+ * @param date The date after which to check for new groups. + * Date format is YYMMDD + * @param time The time after which to check for new groups. + * Time format is HHMMSS using a 24-hour clock. + * @param GMT True if the time is in GMT, false if local server time. + * @param distributions Comma-separated distribution list to check for + * new groups. Set to null if no distributions. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int newgroups(String date, String time, boolean GMT, + String distributions) throws IOException + { + StringBuffer buffer = new StringBuffer(); + + buffer.append(date); + buffer.append(' '); + buffer.append(time); + + if (GMT) + { + buffer.append(' '); + buffer.append("GMT"); + } + + if (distributions != null) + { + buffer.append(" <"); + buffer.append(distributions); + buffer.append('>'); + } + + return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString()); + } + + + /*** + * A convenience method to send the NNTP NEWGROUPS command to the server, + * receive the reply, and return the reply code. + *

+ * @param newsgroups A comma-separated list of newsgroups to check for new + * news. + * @param date The date after which to check for new news. + * Date format is YYMMDD + * @param time The time after which to check for new news. + * Time format is HHMMSS using a 24-hour clock. + * @param GMT True if the time is in GMT, false if local server time. + * @param distributions Comma-separated distribution list to check for + * new news. Set to null if no distributions. + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int newnews(String newsgroups, String date, String time, boolean GMT, + String distributions) throws IOException + { + StringBuffer buffer = new StringBuffer(); + + buffer.append(newsgroups); + buffer.append(' '); + buffer.append(date); + buffer.append(' '); + buffer.append(time); + + if (GMT) + { + buffer.append(' '); + buffer.append("GMT"); + } + + if (distributions != null) + { + buffer.append(" <"); + buffer.append(distributions); + buffer.append('>'); + } + + return sendCommand(NNTPCommand.NEWNEWS, buffer.toString()); + } + + + + /*** + * A convenience method to send the NNTP POST command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int post() throws IOException + { + return sendCommand(NNTPCommand.POST); + } + + + + /*** + * A convenience method to send the NNTP QUIT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int quit() throws IOException + { + return sendCommand(NNTPCommand.QUIT); + } + + /*** + * A convenience method to send the AUTHINFO USER command to the server, + * receive the reply, and return the reply code. (See RFC 2980) + *

+ * @param username A valid username. + * @return The reply code received from the server. The server should + * return a 381 or 281 for this command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int authinfoUser(String username) throws IOException { + String userParameter = "USER " + username; + return sendCommand(NNTPCommand.AUTHINFO, userParameter); + } + + /*** + * A convenience method to send the AUTHINFO PASS command to the server, + * receive the reply, and return the reply code. If this step is + * required, it should immediately follow the AUTHINFO USER command + * (See RFC 2980) + *

+ * @param password a valid password. + * @return The reply code received from the server. The server should + * return a 281 or 502 for this command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int authinfoPass(String password) throws IOException { + String passParameter = "PASS " + password; + return sendCommand(NNTPCommand.AUTHINFO, passParameter); + } + + /*** + * A convenience method to send the NNTP XOVER command to the server, + * receive the reply, and return the reply code. + *

+ * @param selectedArticles a String representation of the range of + * article headers required. This may be an article number, or a + * range of article numbers in the form "XXXX-YYYY", where XXXX + * and YYYY are valid article numbers in the current group. It + * also may be of the form "XXX-", meaning "return XXX and all + * following articles" In this revision, the last format is not + * possible (yet). + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int xover(String selectedArticles) throws IOException { + return sendCommand(NNTPCommand.XOVER, selectedArticles); + } + + /*** + * A convenience method to send the NNTP XHDR command to the server, + * receive the reply, and return the reply code. + *

+ * @param header a String naming a header line (e.g., "subject"). See + * RFC-1036 for a list of valid header lines. + * @param selectedArticles a String representation of the range of + * article headers required. This may be an article number, or a + * range of article numbers in the form "XXXX-YYYY", where XXXX + * and YYYY are valid article numbers in the current group. It + * also may be of the form "XXX-", meaning "return XXX and all + * following articles" In this revision, the last format is not + * possible (yet). + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int xhdr(String header, String selectedArticles) throws IOException { + StringBuffer command = new StringBuffer(header); + command.append(" "); + command.append(selectedArticles); + return sendCommand(NNTPCommand.XHDR, command.toString()); + } + + /** + * A convenience wrapper for the extended LIST command that takes + * an argument, allowing us to selectively list multiple groups. + *

+ * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for + * details. + * @return the reply code received from the server. + * @throws IOException + */ + public int listActive(String wildmat) throws IOException { + StringBuffer command = new StringBuffer("ACTIVE "); + command.append(wildmat); + return sendCommand(NNTPCommand.LIST, command.toString()); + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/nntp/NNTPClient.java b/org/apache/commons/net/nntp/NNTPClient.java new file mode 100644 index 0000000..e10ce90 --- /dev/null +++ b/org/apache/commons/net/nntp/NNTPClient.java @@ -0,0 +1,1285 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.io.DotTerminatedMessageReader; +import org.apache.commons.net.io.DotTerminatedMessageWriter; +import org.apache.commons.net.io.Util; + +/*** + * NNTPClient encapsulates all the functionality necessary to post and + * retrieve articles from an NNTP server. As with all classes derived + * from {@link org.apache.commons.net.SocketClient}, + * you must first connect to the server with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before doing anything, and finally + * {@link org.apache.commons.net.nntp.NNTP#disconnect disconnect() } + * after you're completely finished interacting with the server. + * Remember that the + * {@link org.apache.commons.net.nntp.NNTP#isAllowedToPost isAllowedToPost()} + * method is defined in + * {@link org.apache.commons.net.nntp.NNTP}. + *

+ * You should keep in mind that the NNTP server may choose to prematurely + * close a connection if the client has been idle for longer than a + * given time period or if the server is being shutdown by the operator or + * some other reason. The NNTP class will detect a + * premature NNTP server connection closing when it receives a + * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } + * response to a command. + * When that occurs, the NNTP class method encountering that reply will throw + * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} + * . + * NNTPConectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} + * , you must disconnect the connection with + * {@link org.apache.commons.net.nntp.NNTP#disconnect disconnect() } + * to properly clean up the + * system resources used by NNTP. Before disconnecting, you may check the + * last reply code and text with + * {@link org.apache.commons.net.nntp.NNTP#getReplyCode getReplyCode } and + * {@link org.apache.commons.net.nntp.NNTP#getReplyString getReplyString }. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @author Ted Wise + * @see NNTP + * @see NNTPConnectionClosedException + * @see org.apache.commons.net.MalformedServerReplyException + ***/ + +public class NNTPClient extends NNTP +{ + + private void __parseArticlePointer(String reply, ArticlePointer pointer) + throws MalformedServerReplyException + { + StringTokenizer tokenizer; + + // Do loop is a kluge to simulate goto + do + { + tokenizer = new StringTokenizer(reply); + + if (tokenizer.countTokens() < 3) + break; + + // Skip numeric response value + tokenizer.nextToken(); + // Get article number + try + { + pointer.articleNumber = Integer.parseInt(tokenizer.nextToken()); + } + catch (NumberFormatException e) + { + break; + } + + // Get article id + pointer.articleId = tokenizer.nextToken(); + return ; + } + while (false); + + throw new MalformedServerReplyException( + "Could not parse article pointer.\nServer reply: " + reply); + } + + + private void __parseGroupReply(String reply, NewsgroupInfo info) + throws MalformedServerReplyException + { + String count, first, last; + StringTokenizer tokenizer; + + // Do loop is a kluge to simulate goto + do + { + tokenizer = new StringTokenizer(reply); + + if (tokenizer.countTokens() < 5) + break; + + // Skip numeric response value + tokenizer.nextToken(); + // Get estimated article count + count = tokenizer.nextToken(); + // Get first article number + first = tokenizer.nextToken(); + // Get last article number + last = tokenizer.nextToken(); + // Get newsgroup name + info._setNewsgroup(tokenizer.nextToken()); + + try + { + info._setArticleCount(Integer.parseInt(count)); + info._setFirstArticle(Integer.parseInt(first)); + info._setLastArticle(Integer.parseInt(last)); + } + catch (NumberFormatException e) + { + break; + } + + info._setPostingPermission(NewsgroupInfo.UNKNOWN_POSTING_PERMISSION); + return ; + } + while (false); + + throw new MalformedServerReplyException( + "Could not parse newsgroup info.\nServer reply: " + reply); + } + + + private NewsgroupInfo __parseNewsgroupListEntry(String entry) + { + NewsgroupInfo result; + StringTokenizer tokenizer; + int lastNum, firstNum; + String last, first, permission; + + result = new NewsgroupInfo(); + tokenizer = new StringTokenizer(entry); + + if (tokenizer.countTokens() < 4) + return null; + + result._setNewsgroup(tokenizer.nextToken()); + last = tokenizer.nextToken(); + first = tokenizer.nextToken(); + permission = tokenizer.nextToken(); + + try + { + lastNum = Integer.parseInt(last); + firstNum = Integer.parseInt(first); + result._setFirstArticle(firstNum); + result._setLastArticle(lastNum); + + if((firstNum == 0) && (lastNum == 0)) + result._setArticleCount(0); + else + result._setArticleCount(lastNum - firstNum + 1); + } + catch (NumberFormatException e) + { + return null; + } + + switch (permission.charAt(0)) + { + case 'y': + case 'Y': + result._setPostingPermission( + NewsgroupInfo.PERMITTED_POSTING_PERMISSION); + break; + case 'n': + case 'N': + result._setPostingPermission( + NewsgroupInfo.PROHIBITED_POSTING_PERMISSION); + break; + case 'm': + case 'M': + result._setPostingPermission( + NewsgroupInfo.MODERATED_POSTING_PERMISSION); + break; + default: + result._setPostingPermission( + NewsgroupInfo.UNKNOWN_POSTING_PERMISSION); + break; + } + + return result; + } + + private NewsgroupInfo[] __readNewsgroupListing() throws IOException + { + int size; + String line; + Vector list; + BufferedReader reader; + NewsgroupInfo tmp, info[]; + + reader = new BufferedReader(new DotTerminatedMessageReader(_reader_)); + // Start of with a big vector because we may be reading a very large + // amount of groups. + list = new Vector(2048); + + while ((line = reader.readLine()) != null) + { + tmp = __parseNewsgroupListEntry(line); + if (tmp != null) + list.addElement(tmp); + else + throw new MalformedServerReplyException(line); + } + + if ((size = list.size()) < 1) + return new NewsgroupInfo[0]; + + info = new NewsgroupInfo[size]; + list.copyInto(info); + + return info; + } + + + private Reader __retrieve(int command, + String articleId, ArticlePointer pointer) + throws IOException + { + Reader reader; + + if (articleId != null) + { + if (!NNTPReply.isPositiveCompletion(sendCommand(command, articleId))) + return null; + } + else + { + if (!NNTPReply.isPositiveCompletion(sendCommand(command))) + return null; + } + + + if (pointer != null) + __parseArticlePointer(getReplyString(), pointer); + + reader = new DotTerminatedMessageReader(_reader_); + return reader; + } + + + private Reader __retrieve(int command, + int articleNumber, ArticlePointer pointer) + throws IOException + { + Reader reader; + + if (!NNTPReply.isPositiveCompletion(sendCommand(command, + Integer.toString(articleNumber)))) + return null; + + if (pointer != null) + __parseArticlePointer(getReplyString(), pointer); + + reader = new DotTerminatedMessageReader(_reader_); + return reader; + } + + + + /*** + * Retrieves an article from the NNTP server. The article is referenced + * by its unique article identifier (including the enclosing < and >). + * The article number and identifier contained in the server reply + * are returned through an ArticlePointer. The articleId + * field of the ArticlePointer cannot always be trusted because some + * NNTP servers do not correctly follow the RFC 977 reply format. + *

+ * A DotTerminatedMessageReader is returned from which the article can + * be read. If the article does not exist, null is returned. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The NNTP protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the NNTP connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param articleId The unique article identifier of the article to + * retrieve. If this parameter is null, the currently selected + * article is retrieved. + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return A DotTerminatedMessageReader instance from which the article + * be read. null if the article does not exist. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Reader retrieveArticle(String articleId, ArticlePointer pointer) + throws IOException + { + return __retrieve(NNTPCommand.ARTICLE, articleId, pointer); + + } + + /*** Same as retrieveArticle(articleId, null) ***/ + public Reader retrieveArticle(String articleId) throws IOException + { + return retrieveArticle(articleId, null); + } + + /*** Same as retrieveArticle(null) ***/ + public Reader retrieveArticle() throws IOException + { + return retrieveArticle(null); + } + + + /*** + * Retrieves an article from the currently selected newsgroup. The + * article is referenced by its article number. + * The article number and identifier contained in the server reply + * are returned through an ArticlePointer. The articleId + * field of the ArticlePointer cannot always be trusted because some + * NNTP servers do not correctly follow the RFC 977 reply format. + *

+ * A DotTerminatedMessageReader is returned from which the article can + * be read. If the article does not exist, null is returned. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The NNTP protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the NNTP connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param articleNumber The number of the the article to + * retrieve. + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return A DotTerminatedMessageReader instance from which the article + * be read. null if the article does not exist. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Reader retrieveArticle(int articleNumber, ArticlePointer pointer) + throws IOException + { + return __retrieve(NNTPCommand.ARTICLE, articleNumber, pointer); + } + + /*** Same as retrieveArticle(articleNumber, null) ***/ + public Reader retrieveArticle(int articleNumber) throws IOException + { + return retrieveArticle(articleNumber, null); + } + + + + /*** + * Retrieves an article header from the NNTP server. The article is + * referenced + * by its unique article identifier (including the enclosing < and >). + * The article number and identifier contained in the server reply + * are returned through an ArticlePointer. The articleId + * field of the ArticlePointer cannot always be trusted because some + * NNTP servers do not correctly follow the RFC 977 reply format. + *

+ * A DotTerminatedMessageReader is returned from which the article can + * be read. If the article does not exist, null is returned. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The NNTP protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the NNTP connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param articleId The unique article identifier of the article whose + * header is being retrieved. If this parameter is null, the + * header of the currently selected article is retrieved. + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return A DotTerminatedMessageReader instance from which the article + * header can be read. null if the article does not exist. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Reader retrieveArticleHeader(String articleId, ArticlePointer pointer) + throws IOException + { + return __retrieve(NNTPCommand.HEAD, articleId, pointer); + + } + + /*** Same as retrieveArticleHeader(articleId, null) ***/ + public Reader retrieveArticleHeader(String articleId) throws IOException + { + return retrieveArticleHeader(articleId, null); + } + + /*** Same as retrieveArticleHeader(null) ***/ + public Reader retrieveArticleHeader() throws IOException + { + return retrieveArticleHeader(null); + } + + + /*** + * Retrieves an article header from the currently selected newsgroup. The + * article is referenced by its article number. + * The article number and identifier contained in the server reply + * are returned through an ArticlePointer. The articleId + * field of the ArticlePointer cannot always be trusted because some + * NNTP servers do not correctly follow the RFC 977 reply format. + *

+ * A DotTerminatedMessageReader is returned from which the article can + * be read. If the article does not exist, null is returned. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The NNTP protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the NNTP connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param articleNumber The number of the the article whose header is + * being retrieved. + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return A DotTerminatedMessageReader instance from which the article + * header can be read. null if the article does not exist. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Reader retrieveArticleHeader(int articleNumber, + ArticlePointer pointer) + throws IOException + { + return __retrieve(NNTPCommand.HEAD, articleNumber, pointer); + } + + + /*** Same as retrieveArticleHeader(articleNumber, null) ***/ + public Reader retrieveArticleHeader(int articleNumber) throws IOException + { + return retrieveArticleHeader(articleNumber, null); + } + + + + /*** + * Retrieves an article body from the NNTP server. The article is + * referenced + * by its unique article identifier (including the enclosing < and >). + * The article number and identifier contained in the server reply + * are returned through an ArticlePointer. The articleId + * field of the ArticlePointer cannot always be trusted because some + * NNTP servers do not correctly follow the RFC 977 reply format. + *

+ * A DotTerminatedMessageReader is returned from which the article can + * be read. If the article does not exist, null is returned. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The NNTP protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the NNTP connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param articleId The unique article identifier of the article whose + * body is being retrieved. If this parameter is null, the + * body of the currently selected article is retrieved. + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return A DotTerminatedMessageReader instance from which the article + * body can be read. null if the article does not exist. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Reader retrieveArticleBody(String articleId, ArticlePointer pointer) + throws IOException + { + return __retrieve(NNTPCommand.BODY, articleId, pointer); + + } + + /*** Same as retrieveArticleBody(articleId, null) ***/ + public Reader retrieveArticleBody(String articleId) throws IOException + { + return retrieveArticleBody(articleId, null); + } + + /*** Same as retrieveArticleBody(null) ***/ + public Reader retrieveArticleBody() throws IOException + { + return retrieveArticleBody(null); + } + + + /*** + * Retrieves an article body from the currently selected newsgroup. The + * article is referenced by its article number. + * The article number and identifier contained in the server reply + * are returned through an ArticlePointer. The articleId + * field of the ArticlePointer cannot always be trusted because some + * NNTP servers do not correctly follow the RFC 977 reply format. + *

+ * A DotTerminatedMessageReader is returned from which the article can + * be read. If the article does not exist, null is returned. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The NNTP protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the NNTP connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param articleNumber The number of the the article whose body is + * being retrieved. + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return A DotTerminatedMessageReader instance from which the article + * body can be read. null if the article does not exist. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Reader retrieveArticleBody(int articleNumber, + ArticlePointer pointer) + throws IOException + { + return __retrieve(NNTPCommand.BODY, articleNumber, pointer); + } + + + /*** Same as retrieveArticleBody(articleNumber, null) ***/ + public Reader retrieveArticleBody(int articleNumber) throws IOException + { + return retrieveArticleBody(articleNumber, null); + } + + + /*** + * Select the specified newsgroup to be the target of for future article + * retrieval and posting operations. Also return the newsgroup + * information contained in the server reply through the info parameter. + *

+ * @param newsgroup The newsgroup to select. + * @param info A parameter through which the newsgroup information of + * the selected newsgroup contained in the server reply is returned. + * Set this to null if you do not desire this information. + * @return True if the newsgroup exists and was selected, false otherwise. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean selectNewsgroup(String newsgroup, NewsgroupInfo info) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(group(newsgroup))) + return false; + + if (info != null) + __parseGroupReply(getReplyString(), info); + + return true; + } + + /*** Same as selectNewsgroup(newsgroup, null) ***/ + public boolean selectNewsgroup(String newsgroup) throws IOException + { + return selectNewsgroup(newsgroup, null); + } + + /*** + * List the command help from the server. + *

+ * @return The sever help information. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String listHelp() throws IOException + { + StringWriter help; + Reader reader; + + if (!NNTPReply.isInformational(help())) + return null; + + help = new StringWriter(); + reader = new DotTerminatedMessageReader(_reader_); + Util.copyReader(reader, help); + reader.close(); + help.close(); + return help.toString(); + } + + + /*** + * Select an article by its unique identifier (including enclosing + * < and >) and return its article number and id through the + * pointer parameter. This is achieved through the STAT command. + * According to RFC 977, this will NOT set the current article pointer + * on the server. To do that, you must reference the article by its + * number. + *

+ * @param articleId The unique article identifier of the article that + * is being selectedd. If this parameter is null, the + * body of the current article is selected + * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return True if successful, false if not. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean selectArticle(String articleId, ArticlePointer pointer) + throws IOException + { + if (articleId != null) + { + if (!NNTPReply.isPositiveCompletion(stat(articleId))) + return false; + } + else + { + if (!NNTPReply.isPositiveCompletion(stat())) + return false; + } + + if (pointer != null) + __parseArticlePointer(getReplyString(), pointer); + + return true; + } + + /**** Same as selectArticle(articleId, null) ***/ + public boolean selectArticle(String articleId) throws IOException + { + return selectArticle(articleId, null); + } + + /**** + * Same as selectArticle(null, articleId) . Useful + * for retrieving the current article number. + ***/ + public boolean selectArticle(ArticlePointer pointer) throws IOException + { + return selectArticle(null, pointer); + } + + + /*** + * Select an article in the currently selected newsgroup by its number. + * and return its article number and id through the + * pointer parameter. This is achieved through the STAT command. + * According to RFC 977, this WILL set the current article pointer + * on the server. Use this command to select an article before retrieving + * it, or to obtain an article's unique identifier given its number. + *

+ * @param articleNumber The number of the article to select from the + * currently selected newsgroup. + * @param pointer A parameter through which to return the article's + * number and unique id. Although the articleId field cannot always + * be trusted because of server deviations from RFC 977 reply formats, + * we haven't found a server that misformats this information in response + * to this particular command. You may set this parameter to null if + * you do not desire to retrieve the returned article information. + * @return True if successful, false if not. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean selectArticle(int articleNumber, ArticlePointer pointer) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(stat(articleNumber))) + return false; + + if (pointer != null) + __parseArticlePointer(getReplyString(), pointer); + + return true; + } + + + /*** Same as selectArticle(articleNumber, null) ***/ + public boolean selectArticle(int articleNumber) throws IOException + { + return selectArticle(articleNumber, null); + } + + + /*** + * Select the article preceeding the currently selected article in the + * currently selected newsgroup and return its number and unique id + * through the pointer parameter. Because of deviating server + * implementations, the articleId information cannot be trusted. To + * obtain the article identifier, issue a + * selectArticle(pointer.articleNumber, pointer) immediately + * afterward. + *

+ * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return True if successful, false if not (e.g., there is no previous + * article). + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean selectPreviousArticle(ArticlePointer pointer) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(last())) + return false; + + if (pointer != null) + __parseArticlePointer(getReplyString(), pointer); + + return true; + } + + /*** Same as selectPreviousArticle(null) ***/ + public boolean selectPreviousArticle() throws IOException + { + return selectPreviousArticle(null); + } + + + /*** + * Select the article following the currently selected article in the + * currently selected newsgroup and return its number and unique id + * through the pointer parameter. Because of deviating server + * implementations, the articleId information cannot be trusted. To + * obtain the article identifier, issue a + * selectArticle(pointer.articleNumber, pointer) immediately + * afterward. + *

+ * @param pointer A parameter through which to return the article's + * number and unique id. The articleId field cannot always be trusted + * because of server deviations from RFC 977 reply formats. You may + * set this parameter to null if you do not desire to retrieve the + * returned article information. + * @return True if successful, false if not (e.g., there is no following + * article). + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean selectNextArticle(ArticlePointer pointer) throws IOException + { + if (!NNTPReply.isPositiveCompletion(next())) + return false; + + if (pointer != null) + __parseArticlePointer(getReplyString(), pointer); + + return true; + } + + + /*** Same as selectNextArticle(null) ***/ + public boolean selectNextArticle() throws IOException + { + return selectNextArticle(null); + } + + + /*** + * List all newsgroups served by the NNTP server. If no newsgroups + * are served, a zero length array will be returned. If the command + * fails, null will be returned. + *

+ * @return An array of NewsgroupInfo instances containing the information + * for each newsgroup served by the NNTP server. If no newsgroups + * are served, a zero length array will be returned. If the command + * fails, null will be returned. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public NewsgroupInfo[] listNewsgroups() throws IOException + { + if (!NNTPReply.isPositiveCompletion(list())) + return null; + + return __readNewsgroupListing(); + } + + /** + * An overloaded listNewsgroups() command that allows us to + * specify with a pattern what groups we want to list. Wraps the + * LIST ACTIVE command. + *

+ * @param wildmat a pseudo-regex pattern (cf. RFC 2980) + * @return An array of NewsgroupInfo instances containing the information + * for each newsgroup served by the NNTP server corresponding to the + * supplied pattern. If no such newsgroups are served, a zero length + * array will be returned. If the command fails, null will be returned. + * @throws IOException + */ + public NewsgroupInfo[] listNewsgroups(String wildmat) throws IOException + { + if(!NNTPReply.isPositiveCompletion(listActive(wildmat))) + return null; + return __readNewsgroupListing(); + } + + + /*** + * List all new newsgroups added to the NNTP server since a particular + * date subject to the conditions of the specified query. If no new + * newsgroups were added, a zero length array will be returned. If the + * command fails, null will be returned. + *

+ * @param query The query restricting how to search for new newsgroups. + * @return An array of NewsgroupInfo instances containing the information + * for each new newsgroup added to the NNTP server. If no newsgroups + * were added, a zero length array will be returned. If the command + * fails, null will be returned. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public NewsgroupInfo[] listNewNewsgroups(NewGroupsOrNewsQuery query) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(newgroups( + query.getDate(), query.getTime(), + query.isGMT(), query.getDistributions()))) + return null; + + return __readNewsgroupListing(); + } + + + /*** + * List all new articles added to the NNTP server since a particular + * date subject to the conditions of the specified query. If no new + * new news is found, a zero length array will be returned. If the + * command fails, null will be returned. You must add at least one + * newsgroup to the query, else the command will fail. Each String + * in the returned array is a unique message identifier including the + * enclosing < and >. + *

+ * @param query The query restricting how to search for new news. You + * must add at least one newsgroup to the query. + * @return An array of String instances containing the unique message + * identifiers for each new article added to the NNTP server. If no + * new news is found, a zero length array will be returned. If the + * command fails, null will be returned. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String[] listNewNews(NewGroupsOrNewsQuery query) + throws IOException + { + int size; + String line; + Vector list; + String[] result; + BufferedReader reader; + + if (!NNTPReply.isPositiveCompletion(newnews( + query.getNewsgroups(), query.getDate(), query.getTime(), + query.isGMT(), query.getDistributions()))) + return null; + + list = new Vector(); + reader = new BufferedReader(new DotTerminatedMessageReader(_reader_)); + + while ((line = reader.readLine()) != null) + list.addElement(line); + + size = list.size(); + + if (size < 1) + return new String[0]; + + result = new String[size]; + list.copyInto(result); + + return result; + } + + /*** + * There are a few NNTPClient methods that do not complete the + * entire sequence of NNTP commands to complete a transaction. These + * commands require some action by the programmer after the reception + * of a positive preliminary command. After the programmer's code + * completes its actions, it must call this method to receive + * the completion reply from the server and verify the success of the + * entire transaction. + *

+ * For example + *

+     * writer = client.postArticle();
+     * if(writer == null) // failure
+     *   return false;
+     * header = new SimpleNNTPHeader("foobar@foo.com", "Just testing");
+     * header.addNewsgroup("alt.test");
+     * writer.write(header.toString());
+     * writer.write("This is just a test");
+     * writer.close();
+     * if(!client.completePendingCommand()) // failure
+     *   return false;
+     * 
+ *

+ * @return True if successfully completed, false if not. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean completePendingCommand() throws IOException + { + return NNTPReply.isPositiveCompletion(getReply()); + } + + /*** + * Post an article to the NNTP server. This method returns a + * DotTerminatedMessageWriter instance to which the article can be + * written. Null is returned if the posting attempt fails. You + * should check {@link NNTP#isAllowedToPost isAllowedToPost() } + * before trying to post. However, a posting + * attempt can fail due to malformed headers. + *

+ * You must not issue any commands to the NNTP server (i.e., call any + * (other methods) until you finish writing to the returned Writer + * instance and close it. The NNTP protocol uses the same stream for + * issuing commands as it does for returning results. Therefore the + * returned Writer actually writes directly to the NNTP connection. + * After you close the writer, you can execute new commands. If you + * do not follow these requirements your program will not work properly. + *

+ * Different NNTP servers will require different header formats, but + * you can use the provided + * {@link org.apache.commons.net.nntp.SimpleNNTPHeader} + * class to construct the bare minimum acceptable header for most + * news readers. To construct more complicated headers you should + * refer to RFC 822. When the Java Mail API is finalized, you will be + * able to use it to compose fully compliant Internet text messages. + * The DotTerminatedMessageWriter takes care of doubling line-leading + * dots and ending the message with a single dot upon closing, so all + * you have to worry about is writing the header and the message. + *

+ * Upon closing the returned Writer, you need to call + * {@link #completePendingCommand completePendingCommand() } + * to finalize the posting and verify its success or failure from + * the server reply. + *

+ * @return A DotTerminatedMessageWriter to which the article (including + * header) can be written. Returns null if the command fails. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + + public Writer postArticle() throws IOException + { + if (!NNTPReply.isPositiveIntermediate(post())) + return null; + + return new DotTerminatedMessageWriter(_writer_); + } + + + public Writer forwardArticle(String articleId) throws IOException + { + if (!NNTPReply.isPositiveIntermediate(ihave(articleId))) + return null; + + return new DotTerminatedMessageWriter(_writer_); + } + + + /*** + * Logs out of the news server gracefully by sending the QUIT command. + * However, you must still disconnect from the server before you can open + * a new connection. + *

+ * @return True if successfully completed, false if not. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean logout() throws IOException + { + return NNTPReply.isPositiveCompletion(quit()); + } + + + /** + * Log into a news server by sending the AUTHINFO USER/AUTHINFO + * PASS command sequence. This is usually sent in response to a + * 480 reply code from the NNTP server. + *

+ * @param username a valid username + * @param password the corresponding password + * @return True for successful login, false for a failure + * @throws IOException + */ + public boolean authenticate(String username, String password) + throws IOException + { + int replyCode = authinfoUser(username); + + if (replyCode == NNTPReply.MORE_AUTH_INFO_REQUIRED) + { + replyCode = authinfoPass(password); + + if (replyCode == NNTPReply.AUTHENTICATION_ACCEPTED) + { + _isAllowedToPost = true; + return true; + } + } + return false; + } + + /*** + * Private implementation of XOVER functionality. + * + * See {@link NNTP#xover} + * for legal agument formats. Alternatively, read RFC 2980 :-) + *

+ * @param articleRange + * @return Returns a DotTerminatedMessageReader if successful, null + * otherwise + * @exception IOException + */ + private Reader __retrieveArticleInfo(String articleRange) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(xover(articleRange))) + return null; + + return new DotTerminatedMessageReader(_reader_); + } + + /** + * Return article headers for a specified post. + *

+ * @param articleNumber the article to retrieve headers for + * @return a DotTerminatedReader if successful, null otherwise + * @throws IOException + */ + public Reader retrieveArticleInfo(int articleNumber) throws IOException + { + return __retrieveArticleInfo(Integer.toString(articleNumber)); + } + + /** + * Return article headers for all articles between lowArticleNumber + * and highArticleNumber, inclusively. + *

+ * @param lowArticleNumber + * @param highArticleNumber + * @return a DotTerminatedReader if successful, null otherwise + * @throws IOException + */ + public Reader retrieveArticleInfo(int lowArticleNumber, + int highArticleNumber) + throws IOException + { + return + __retrieveArticleInfo(lowArticleNumber + "-" + + highArticleNumber); + } + + /*** + * Private implementation of XHDR functionality. + * + * See {@link NNTP#xhdr} + * for legal agument formats. Alternatively, read RFC 1036. + *

+ * @param header + * @param articleRange + * @return Returns a DotTerminatedMessageReader if successful, null + * otherwise + * @exception IOException + */ + private Reader __retrieveHeader(String header, String articleRange) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(xhdr(header, articleRange))) + return null; + + return new DotTerminatedMessageReader(_reader_); + } + + /** + * Return an article header for a specified post. + *

+ * @param header the header to retrieve + * @param articleNumber the article to retrieve the header for + * @return a DotTerminatedReader if successful, null otherwise + * @throws IOException + */ + public Reader retrieveHeader(String header, int articleNumber) + throws IOException + { + return __retrieveHeader(header, Integer.toString(articleNumber)); + } + + /** + * Return an article header for all articles between lowArticleNumber + * and highArticleNumber, inclusively. + *

+ * @param header + * @param lowArticleNumber + * @param highArticleNumber + * @return a DotTerminatedReader if successful, null otherwise + * @throws IOException + */ + public Reader retrieveHeader(String header, int lowArticleNumber, + int highArticleNumber) + throws IOException + { + return + __retrieveHeader(header,lowArticleNumber + "-" + highArticleNumber); + } +} + + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/nntp/NNTPCommand.java b/org/apache/commons/net/nntp/NNTPCommand.java new file mode 100644 index 0000000..09f4015 --- /dev/null +++ b/org/apache/commons/net/nntp/NNTPCommand.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +/*** + * NNTPCommand stores a set of constants for NNTP command codes. To interpret + * the meaning of the codes, familiarity with RFC 977 is assumed. + *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @author Ted Wise + ***/ + +public final class NNTPCommand +{ + + public static final int ARTICLE = 0; + public static final int BODY = 1; + public static final int GROUP = 2; + public static final int HEAD = 3; + public static final int HELP = 4; + public static final int IHAVE = 5; + public static final int LAST = 6; + public static final int LIST = 7; + public static final int NEWGROUPS = 8; + public static final int NEWNEWS = 9; + public static final int NEXT = 10; + public static final int POST = 11; + public static final int QUIT = 12; + public static final int SLAVE = 13; + public static final int STAT = 14; + public static final int AUTHINFO = 15; + public static final int XOVER = 16; + public static final int XHDR = 17; + + // Cannot be instantiated + private NNTPCommand() + {} + + static final String[] _commands = { + "ARTICLE", "BODY", "GROUP", "HEAD", "HELP", "IHAVE", "LAST", "LIST", + "NEWGROUPS", "NEWNEWS", "NEXT", "POST", "QUIT", "SLAVE", "STAT", + "AUTHINFO", "XOVER", "XHDR" + }; + + + /*** + * Retrieve the NNTP protocol command string corresponding to a specified + * command code. + *

+ * @param command The command code. + * @return The NNTP protcol command string corresponding to a specified + * command code. + ***/ + public static final String getCommand(int command) + { + return _commands[command]; + } + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/nntp/NNTPConnectionClosedException.java b/org/apache/commons/net/nntp/NNTPConnectionClosedException.java new file mode 100644 index 0000000..948ed12 --- /dev/null +++ b/org/apache/commons/net/nntp/NNTPConnectionClosedException.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +import java.io.IOException; + +/*** + * NNTPConnectionClosedException is used to indicate the premature or + * unexpected closing of an NNTP connection resulting from a + * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } + * response (NNTP reply code 400) to a + * failed NNTP command. This exception is derived from IOException and + * therefore may be caught either as an IOException or specifically as an + * NNTPConnectionClosedException. + *

+ *

+ * @author Daniel F. Savarese + * @see NNTP + * @see NNTPClient + ***/ + +public final class NNTPConnectionClosedException extends IOException +{ + + /*** Constructs a NNTPConnectionClosedException with no message ***/ + public NNTPConnectionClosedException() + { + super(); + } + + /*** + * Constructs a NNTPConnectionClosedException with a specified message. + *

+ * @param message The message explaining the reason for the exception. + ***/ + public NNTPConnectionClosedException(String message) + { + super(message); + } + +} diff --git a/org/apache/commons/net/nntp/NNTPReply.java b/org/apache/commons/net/nntp/NNTPReply.java new file mode 100644 index 0000000..f7d0fbd --- /dev/null +++ b/org/apache/commons/net/nntp/NNTPReply.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +/*** + * NNTPReply stores a set of constants for NNTP reply codes. To interpret + * the meaning of the codes, familiarity with RFC 977 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 977. For those who think in terms of the actual reply code values, + * a set of CODE_NUM constants are provided where NUM is the numerical value + * of the code. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class NNTPReply +{ + + public static final int CODE_100 = 100; + public static final int CODE_199 = 199; + public static final int CODE_200 = 200; + public static final int CODE_201 = 201; + public static final int CODE_202 = 202; + public static final int CODE_205 = 205; + public static final int CODE_211 = 211; + public static final int CODE_215 = 215; + public static final int CODE_220 = 220; + public static final int CODE_221 = 221; + public static final int CODE_222 = 222; + public static final int CODE_223 = 223; + public static final int CODE_230 = 230; + public static final int CODE_231 = 231; + public static final int CODE_235 = 235; + public static final int CODE_240 = 240; + public static final int CODE_281 = 281; + public static final int CODE_335 = 335; + public static final int CODE_340 = 340; + public static final int CODE_381 = 381; + public static final int CODE_400 = 400; + public static final int CODE_408 = 408; + public static final int CODE_411 = 411; + public static final int CODE_412 = 412; + public static final int CODE_420 = 420; + public static final int CODE_421 = 421; + public static final int CODE_422 = 422; + public static final int CODE_423 = 423; + public static final int CODE_430 = 430; + public static final int CODE_435 = 435; + public static final int CODE_436 = 436; + public static final int CODE_437 = 437; + public static final int CODE_440 = 440; + public static final int CODE_441 = 441; + public static final int CODE_482 = 482; + public static final int CODE_500 = 500; + public static final int CODE_501 = 501; + public static final int CODE_502 = 502; + public static final int CODE_503 = 503; + + public static final int HELP_TEXT_FOLLOWS = CODE_100; + public static final int DEBUG_OUTPUT = CODE_199; + public static final int SERVER_READY_POSTING_ALLOWED = CODE_200; + public static final int SERVER_READY_POSTING_NOT_ALLOWED = CODE_201; + public static final int SLAVE_STATUS_NOTED = CODE_202; + public static final int CLOSING_CONNECTION = CODE_205; + public static final int GROUP_SELECTED = CODE_211; + public static final int ARTICLE_RETRIEVED_HEAD_AND_BODY_FOLLOW = CODE_220; + public static final int ARTICLE_RETRIEVED_HEAD_FOLLOWS = CODE_221; + public static final int ARTICLE_RETRIEVED_BODY_FOLLOWS = CODE_222; + public static final int + ARTICLE_RETRIEVED_REQUEST_TEXT_SEPARATELY = CODE_223; + public static final int ARTICLE_LIST_BY_MESSAGE_ID_FOLLOWS = CODE_230; + public static final int NEW_NEWSGROUP_LIST_FOLLOWS = CODE_231; + public static final int ARTICLE_TRANSFERRED_OK = CODE_235; + public static final int ARTICLE_POSTED_OK = CODE_240; + public static final int AUTHENTICATION_ACCEPTED = CODE_281; + public static final int SEND_ARTICLE_TO_TRANSFER = CODE_335; + public static final int SEND_ARTICLE_TO_POST = CODE_340; + public static final int MORE_AUTH_INFO_REQUIRED = CODE_381; + public static final int SERVICE_DISCONTINUED = CODE_400; + public static final int NO_SUCH_NEWSGROUP = CODE_411; + public static final int AUTHENTICATION_REQUIRED = CODE_408; + public static final int NO_NEWSGROUP_SELECTED = CODE_412; + public static final int NO_CURRENT_ARTICLE_SELECTED = CODE_420; + public static final int NO_NEXT_ARTICLE = CODE_421; + public static final int NO_PREVIOUS_ARTICLE = CODE_422; + public static final int NO_SUCH_ARTICLE_NUMBER = CODE_423; + public static final int NO_SUCH_ARTICLE_FOUND = CODE_430; + public static final int ARTICLE_NOT_WANTED = CODE_435; + public static final int TRANSFER_FAILED = CODE_436; + public static final int ARTICLE_REJECTED = CODE_437; + public static final int POSTING_NOT_ALLOWED = CODE_440; + public static final int POSTING_FAILED = CODE_441; + public static final int AUTHENTICATION_REJECTED = CODE_482; + public static final int COMMAND_NOT_RECOGNIZED = CODE_500; + public static final int COMMAND_SYNTAX_ERROR = CODE_501; + public static final int PERMISSION_DENIED = CODE_502; + public static final int PROGRAM_FAULT = CODE_503; + + // Cannot be instantiated + + private NNTPReply() + {} + + /*** + * Determine if a reply code is an informational response. All + * codes beginning with a 1 are positive informational responses. + * Informational responses are used to provide human readable + * information such as help text. + *

+ * @param reply The reply code to test. + * @return True if a reply code is an informational response, false + * if not. + ***/ + public static boolean isInformational(int reply) + { + return (reply >= 100 && reply < 200); + } + + /*** + * Determine if a reply code is a positive completion response. All + * codes beginning with a 2 are positive completion responses. + * The NNTP server will send a positive completion response on the final + * successful completion of a command. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive completion response, false + * if not. + ***/ + public static boolean isPositiveCompletion(int reply) + { + return (reply >= 200 && reply < 300); + } + + /*** + * Determine if a reply code is a positive intermediate response. All + * codes beginning with a 3 are positive intermediate responses. + * The NNTP server will send a positive intermediate response on the + * successful completion of one part of a multi-part command or + * sequence of commands. For example, after a successful POST command, + * a positive intermediate response will be sent to indicate that the + * server is ready to receive the article to be posted. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive intermediate response, false + * if not. + ***/ + public static boolean isPositiveIntermediate(int reply) + { + return (reply >= 300 && reply < 400); + } + + /*** + * Determine if a reply code is a negative transient response. All + * codes beginning with a 4 are negative transient responses. + * The NNTP server will send a negative transient response on the + * failure of a correctly formatted command that could not be performed + * for some reason. For example, retrieving an article that does not + * exist will result in a negative transient response. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative transient response, false + * if not. + ***/ + public static boolean isNegativeTransient(int reply) + { + return (reply >= 400 && reply < 500); + } + + /*** + * Determine if a reply code is a negative permanent response. All + * codes beginning with a 5 are negative permanent responses. + * The NNTP server will send a negative permanent response when + * it does not implement a command, a command is incorrectly formatted, + * or a serious program error occurs. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative permanent response, false + * if not. + ***/ + public static boolean isNegativePermanent(int reply) + { + return (reply >= 500 && reply < 600); + } + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java b/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java new file mode 100644 index 0000000..a0d9aeb --- /dev/null +++ b/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +import java.util.Calendar; + +/*** + * The NewGroupsOrNewsQuery class. This is used to issue NNTP NEWGROUPS and + * NEWNEWS queries, implemented by + * {@link org.apache.commons.net.nntp.NNTPClient#listNewNewsgroups listNewNewsGroups } + * and + * {@link org.apache.commons.net.nntp.NNTPClient#listNewNews listNewNews } + * respectively. It prevents you from having to format + * date, time, distribution, and newgroup arguments. + *

+ * You might use the class as follows: + *

+ * query = new NewsGroupsOrNewsQuery(new GregorianCalendar(97, 11, 15), false);
+ * query.addDistribution("comp");
+ * NewsgroupInfo[] newsgroups = client.listNewgroups(query);
+ * 
+ * This will retrieve the list of newsgroups starting with the comp. + * distribution prefix created since midnight 11/15/97. + *

+ *

+ * @author Daniel F. Savarese + * @see NNTPClient + ***/ + +public final class NewGroupsOrNewsQuery +{ + private String __date, __time; + private StringBuffer __distributions; + private StringBuffer __newsgroups; + private boolean __isGMT; + + + /*** + * Creates a new query using the given time as a reference point. + *

+ * @param date The date since which new groups or news have arrived. + * @param gmt True if the date should be considered as GMT, false if not. + ***/ + public NewGroupsOrNewsQuery(Calendar date, boolean gmt) + { + int num; + String str; + StringBuffer buffer; + + __distributions = null; + __newsgroups = null; + __isGMT = gmt; + + buffer = new StringBuffer(); + + // Get year + num = date.get(Calendar.YEAR); + str = Integer.toString(num); + num = str.length(); + + if (num >= 2) + buffer.append(str.substring(num - 2)); + else + buffer.append("00"); + + // Get month + num = date.get(Calendar.MONTH) + 1; + str = Integer.toString(num); + num = str.length(); + + if (num == 1) + { + buffer.append('0'); + buffer.append(str); + } + else if (num == 2) + buffer.append(str); + else + buffer.append("01"); + + // Get day + num = date.get(Calendar.DAY_OF_MONTH); + str = Integer.toString(num); + num = str.length(); + + if (num == 1) + { + buffer.append('0'); + buffer.append(str); + } + else if (num == 2) + buffer.append(str); + else + buffer.append("01"); + + __date = buffer.toString(); + + buffer.setLength(0); + + // Get hour + num = date.get(Calendar.HOUR_OF_DAY); + str = Integer.toString(num); + num = str.length(); + + if (num == 1) + { + buffer.append('0'); + buffer.append(str); + } + else if (num == 2) + buffer.append(str); + else + buffer.append("00"); + + // Get minutes + num = date.get(Calendar.MINUTE); + str = Integer.toString(num); + num = str.length(); + + if (num == 1) + { + buffer.append('0'); + buffer.append(str); + } + else if (num == 2) + buffer.append(str); + else + buffer.append("00"); + + + // Get seconds + num = date.get(Calendar.SECOND); + str = Integer.toString(num); + num = str.length(); + + if (num == 1) + { + buffer.append('0'); + buffer.append(str); + } + else if (num == 2) + buffer.append(str); + else + buffer.append("00"); + + __time = buffer.toString(); + } + + + /*** + * Add a newsgroup to the list of newsgroups being queried. Newsgroups + * added this way are only meaningful to the NEWNEWS command. Newsgroup + * names may include the * wildcard, as in + * comp.lang.* or comp.lang.java.* . Adding + * at least one newsgroup is mandatory for the NEWNEWS command. + *

+ * @param newsgroup The newsgroup to add to the list of groups to be + * checked for new news. + ***/ + public void addNewsgroup(String newsgroup) + { + if (__newsgroups != null) + __newsgroups.append(','); + else + __newsgroups = new StringBuffer(); + __newsgroups.append(newsgroup); + } + + + /*** + * Add a newsgroup to the list of newsgroups being queried, but indicate + * that group should not be checked for new news. Newsgroups + * added this way are only meaningful to the NEWNEWS command. + * Newsgroup names may include the * wildcard, as in + * comp.lang.* or comp.lang.java.* . + *

+ * The following would create a query that searched for new news in + * all comp.lang.java newsgroups except for comp.lang.java.advocacy. + *

+     * query.addNewsgroup("comp.lang.java.*");
+     * query.omitNewsgroup("comp.lang.java.advocacy");
+     * 
+ *

+ * @param newsgroup The newsgroup to add to the list of groups to be + * checked for new news, but which should be omitted from + * the search for new news.. + ***/ + public void omitNewsgroup(String newsgroup) + { + addNewsgroup("!" + newsgroup); + } + + + /*** + * Add a distribution group to the query. The distribution part of a + * newsgroup is the segment of the name preceding the first dot (e.g., + * comp, alt, rec). Only those newsgroups matching one of the + * distributions or, in the case of NEWNEWS, an article in a newsgroup + * matching one of the distributions, will be reported as a query result. + * Adding distributions is purely optional. + *

+ * @param distribution A distribution to add to the query. + ***/ + public void addDistribution(String distribution) + { + if (__distributions != null) + __distributions.append(','); + else + __distributions = new StringBuffer(); + __distributions.append(distribution); + } + + /*** + * Return the NNTP query formatted date (year, month, day in the form + * YYMMDD. + *

+ * @return The NNTP query formatted date. + ***/ + public String getDate() + { + return __date; + } + + /*** + * Return the NNTP query formatted time (hour, minutes, seconds in the form + * HHMMSS. + *

+ * @return The NNTP query formatted time. + ***/ + public String getTime() + { + return __time; + } + + /*** + * Return whether or not the query date should be treated as GMT. + *

+ * @return True if the query date is to be treated as GMT, false if not. + ***/ + public boolean isGMT() + { + return __isGMT; + } + + /*** + * Return the comma separated list of distributions. This may be null + * if there are no distributions. + *

+ * @return The list of distributions, which may be null if no distributions + * have been specified. + ***/ + public String getDistributions() + { + return (__distributions == null ? null : __distributions.toString()); + } + + /*** + * Return the comma separated list of newsgroups. This may be null + * if there are no newsgroups + *

+ * @return The list of newsgroups, which may be null if no newsgroups + * have been specified. + ***/ + public String getNewsgroups() + { + return (__newsgroups == null ? null : __newsgroups.toString()); + } +} diff --git a/org/apache/commons/net/nntp/NewsgroupInfo.java b/org/apache/commons/net/nntp/NewsgroupInfo.java new file mode 100644 index 0000000..aa48d16 --- /dev/null +++ b/org/apache/commons/net/nntp/NewsgroupInfo.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +/*** + * NewsgroupInfo stores information pertaining to a newsgroup returned by + * the NNTP GROUP, LIST, and NEWGROUPS commands, implemented by + * {@link org.apache.commons.net.nntp.NNTPClient#selectNewsgroup selectNewsgroup } + * , + * {@link org.apache.commons.net.nntp.NNTPClient#listNewsgroups listNewsgroups } + * , and + * {@link org.apache.commons.net.nntp.NNTPClient#listNewNewsgroups listNewNewsgroups } + * respectively. + *

+ *

+ * @author Daniel F. Savarese + * @see NNTPClient + ***/ + +public final class NewsgroupInfo +{ + /*** + * A constant indicating that the posting permission of a newsgroup is + * unknown. For example, the NNTP GROUP command does not return posting + * information, so NewsgroupInfo instances obtained from that command + * willhave an UNKNOWN_POSTING_PERMISSION. + ***/ + public static final int UNKNOWN_POSTING_PERMISSION = 0; + + /*** A constant indicating that a newsgroup is moderated. ***/ + public static final int MODERATED_POSTING_PERMISSION = 1; + + /*** A constant indicating that a newsgroup is public and unmoderated. ***/ + public static final int PERMITTED_POSTING_PERMISSION = 2; + + /*** + * A constant indicating that a newsgroup is closed for general posting. + ***/ + public static final int PROHIBITED_POSTING_PERMISSION = 3; + + private String __newsgroup; + private int __estimatedArticleCount; + private int __firstArticle, __lastArticle; + private int __postingPermission; + + void _setNewsgroup(String newsgroup) + { + __newsgroup = newsgroup; + } + + void _setArticleCount(int count) + { + __estimatedArticleCount = count; + } + + void _setFirstArticle(int first) + { + __firstArticle = first; + } + + void _setLastArticle(int last) + { + __lastArticle = last; + } + + void _setPostingPermission(int permission) + { + __postingPermission = permission; + } + + /*** + * Get the newsgroup name. + *

+ * @return The name of the newsgroup. + ***/ + public String getNewsgroup() + { + return __newsgroup; + } + + /*** + * Get the estimated number of articles in the newsgroup. The + * accuracy of this value will depend on the server implementation. + *

+ * @return The estimated number of articles in the newsgroup. + ***/ + public int getArticleCount() + { + return __estimatedArticleCount; + } + + /*** + * Get the number of the first article in the newsgroup. + *

+ * @return The number of the first article in the newsgroup. + ***/ + public int getFirstArticle() + { + return __firstArticle; + } + + /*** + * Get the number of the last article in the newsgroup. + *

+ * @return The number of the last article in the newsgroup. + ***/ + public int getLastArticle() + { + return __lastArticle; + } + + /*** + * Get the posting permission of the newsgroup. This will be one of + * the POSTING_PERMISSION constants. + *

+ * @return The posting permission status of the newsgroup. + ***/ + public int getPostingPermission() + { + return __postingPermission; + } + + /* + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(__newsgroup); + buffer.append(' '); + buffer.append(__lastArticle); + buffer.append(' '); + buffer.append(__firstArticle); + buffer.append(' '); + switch(__postingPermission) { + case 1: buffer.append('m'); break; + case 2: buffer.append('y'); break; + case 3: buffer.append('n'); break; + } + return buffer.toString(); +} + */ +} diff --git a/org/apache/commons/net/nntp/SimpleNNTPHeader.java b/org/apache/commons/net/nntp/SimpleNNTPHeader.java new file mode 100644 index 0000000..d18a8cf --- /dev/null +++ b/org/apache/commons/net/nntp/SimpleNNTPHeader.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +/*** + * This class is used to construct the bare minimum + * acceptable header for most news readers. To construct more + * complicated headers you should refer to RFC 822. When the + * Java Mail API is finalized, you will be + * able to use it to compose fully compliant Internet text messages. + *

+ * The main purpose of the class is to faciliatate the article posting + * process, by relieving the programmer from having to explicitly format + * an article header. For example: + *

+ * writer = client.postArticle();
+ * if(writer == null) // failure
+ *   return false;
+ * header = new SimpleNNTPHeader("foobar@foo.com", "Just testing");
+ * header.addNewsgroup("alt.test");
+ * header.addHeaderField("Organization", "Foobar, Inc.");
+ * writer.write(header.toString());
+ * writer.write("This is just a test");
+ * writer.close();
+ * if(!client.completePendingCommand()) // failure
+ *   return false;
+ * 
+ *

+ *

+ * @author Daniel F. Savarese + * @see NNTPClient + ***/ + +public class SimpleNNTPHeader +{ + private String __subject, __from; + private StringBuilder __newsgroups; + private StringBuilder __headerFields; + private int __newsgroupCount; + + /*** + * Creates a new SimpleNNTPHeader instance initialized with the given + * from and subject header field values. + *

+ * @param from The value of the From: header field. This + * should be the article poster's email address. + * @param subject The value of the Subject: header field. + * This should be the subject of the article. + ***/ + public SimpleNNTPHeader(String from, String subject) + { + __from = from; + __subject = subject; + __newsgroups = new StringBuilder(); + __headerFields = new StringBuilder(); + __newsgroupCount = 0; + } + + /*** + * Adds a newsgroup to the article Newsgroups: field. + *

+ * @param newsgroup The newsgroup to add to the article's newsgroup + * distribution list. + ***/ + public void addNewsgroup(String newsgroup) + { + if (__newsgroupCount++ > 0) + __newsgroups.append(','); + __newsgroups.append(newsgroup); + } + + /*** + * Adds an arbitrary header field with the given value to the article + * header. These headers will be written after the From, Newsgroups, + * and Subject fields when the SimpleNNTPHeader is convertered to a string. + * An example use would be: + *

+     * header.addHeaderField("Organization", "Foobar, Inc.");
+     * 
+ *

+ * @param headerField The header field to add, not including the colon. + * @param value The value of the added header field. + ***/ + public void addHeaderField(String headerField, String value) + { + __headerFields.append(headerField); + __headerFields.append(": "); + __headerFields.append(value); + __headerFields.append('\n'); + } + + + /*** + * Returns the address used in the From: header field. + *

+ * @return The from address. + ***/ + public String getFromAddress() + { + return __from; + } + + /*** + * Returns the subject used in the Subject: header field. + *

+ * @return The subject. + ***/ + public String getSubject() + { + return __subject; + } + + /*** + * Returns the contents of the Newsgroups: header field. + *

+ * @return The comma-separated list of newsgroups to which the article + * is being posted. + ***/ + public String getNewsgroups() + { + return __newsgroups.toString(); + } + + /*** + * Converts the SimpleNNTPHeader to a properly formatted header in + * the form of a String, including the blank line used to separate + * the header from the article body. + *

+ * @return The article header in the form of a String. + ***/ + @Override + public String toString() + { + StringBuffer header = new StringBuffer(); + + header.append("From: "); + header.append(__from); + header.append("\nNewsgroups: "); + header.append(__newsgroups.toString()); + header.append("\nSubject: "); + header.append(__subject); + header.append('\n'); + if (__headerFields.length() > 0) + header.append(__headerFields.toString()); + header.append('\n'); + + return header.toString(); + } +} diff --git a/org/apache/commons/net/nntp/Threadable.java b/org/apache/commons/net/nntp/Threadable.java new file mode 100644 index 0000000..518a9a4 --- /dev/null +++ b/org/apache/commons/net/nntp/Threadable.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +/** + * A placeholder interface for threadable message objects + * Author: Rory Winston + * + */ +public interface Threadable { + public boolean isDummy(); + public String messageThreadId(); + public String[] messageThreadReferences(); + public String simplifiedSubject(); + public boolean subjectIsReply(); + public void setChild(Threadable child); + public void setNext(Threadable next); + public Threadable makeDummy(); +} diff --git a/org/apache/commons/net/nntp/Threader.java b/org/apache/commons/net/nntp/Threader.java new file mode 100644 index 0000000..d702c67 --- /dev/null +++ b/org/apache/commons/net/nntp/Threader.java @@ -0,0 +1,481 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.net.nntp; + +/** + * This is an implementation of a message threading algorithm, as originally devised by Zamie Zawinski. + * See http://www.jwz.org/doc/threading.html for details. + * For his Java implementation, see http://lxr.mozilla.org/mozilla/source/grendel/sources/grendel/view/Threader.java + * + * @author rwinston + * + */ + +import java.util.HashMap; +import java.util.Iterator; + +public class Threader { + private ThreadContainer root; + private HashMap idTable; + private int bogusIdCount = 0; + + /** + * The main threader entry point - The client passes in an array of Threadable objects, and + * the Threader constructs a connected 'graph' of messages + * @param messages + * @return + */ + public Threadable thread(Threadable[] messages) { + if (messages == null) + return null; + + idTable = new HashMap(); + + // walk through each Threadable element + for (int i = 0; i < messages.length; ++i) { + if (!messages[i].isDummy()) + buildContainer(messages[i]); + } + + root = findRootSet(); + idTable.clear(); + idTable = null; + + pruneEmptyContainers(root); + + root.reverseChildren(); + gatherSubjects(); + + if (root.next != null) + throw new RuntimeException("root node has a next:" + root); + + for (ThreadContainer r = root.child; r != null; r = r.next) { + if (r.threadable == null) + r.threadable = r.child.threadable.makeDummy(); + } + + Threadable result = (root.child == null ? null : root.child.threadable); + root.flush(); + root = null; + + return result; + } + + /** + * + * @param threadable + */ + private void buildContainer(Threadable threadable) { + String id = threadable.messageThreadId(); + ThreadContainer container = idTable.get(id); + + // A ThreadContainer exists for this id already. This should be a forward reference, but may + // be a duplicate id, in which case we will need to generate a bogus placeholder id + if (container != null) { + if (container.threadable != null) { // oops! duplicate ids... + id = ""; + container = null; + } else { + // The container just contained a forward reference to this message, so let's + // fill in the threadable field of the container with this message + container.threadable = threadable; + } + } + + // No container exists for that message Id. Create one and insert it into the hash table. + if (container == null) { + container = new ThreadContainer(); + container.threadable = threadable; + idTable.put(id, container); + } + + // Iterate through all of the references and create ThreadContainers for any references that + // don't have them. + ThreadContainer parentRef = null; + { + String[] references = threadable.messageThreadReferences(); + for (int i = 0; i < references.length; ++i) { + String refString = references[i]; + ThreadContainer ref = idTable.get(refString); + + // if this id doesnt have a container, create one + if (ref == null) { + ref = new ThreadContainer(); + idTable.put(refString, ref); + } + + // Link references together in the order they appear in the References: header, + // IF they dont have a have a parent already && + // IF it will not cause a circular reference + if ((parentRef != null) + && (ref.parent == null) + && (parentRef != ref) + && !(parentRef.findChild(ref))) { + // Link ref into the parent's child list + ref.parent = parentRef; + ref.next = parentRef.child; + parentRef.child = ref; + } + parentRef = ref; + } + } + + // parentRef is now set to the container of the last element in the references field. make that + // be the parent of this container, unless doing so causes a circular reference + if (parentRef != null + && (parentRef == container || container.findChild(parentRef))) + parentRef = null; + + // if it has a parent already, its because we saw this message in a References: field, and presumed + // a parent based on the other entries in that field. Now that we have the actual message, we can + // throw away the old parent and use this new one + if (container.parent != null) { + ThreadContainer rest, prev; + + for (prev = null, rest = container.parent.child; + rest != null; + prev = rest, rest = rest.next) { + if (rest == container) + break; + } + + if (rest == null) { + throw new RuntimeException( + "Didnt find " + + container + + " in parent" + + container.parent); + } + + // Unlink this container from the parent's child list + if (prev == null) + container.parent.child = container.next; + else + prev.next = container.next; + + container.next = null; + container.parent = null; + } + + // If we have a parent, link container into the parents child list + if (parentRef != null) { + container.parent = parentRef; + container.next = parentRef.child; + parentRef.child = container; + } + } + + /** + * Find the root set of all existing ThreadContainers + * @return root the ThreadContainer representing the root node + */ + private ThreadContainer findRootSet() { + ThreadContainer root = new ThreadContainer(); + Iterator iter = idTable.keySet().iterator(); + + while (iter.hasNext()) { + Object key = iter.next(); + ThreadContainer c = idTable.get(key); + if (c.parent == null) { + if (c.next != null) + throw new RuntimeException( + "c.next is " + c.next.toString()); + c.next = root.child; + root.child = c; + } + } + return root; + } + + /** + * Delete any empty or dummy ThreadContainers + * @param parent + */ + private void pruneEmptyContainers(ThreadContainer parent) { + ThreadContainer container, prev, next; + for (prev = null, container = parent.child, next = container.next; + container != null; + prev = container, + container = next, + next = (container == null ? null : container.next)) { + + // Is it empty and without any children? If so,delete it + if (container.threadable == null && container.child == null) { + if (prev == null) + parent.child = container.next; + else + prev.next = container.next; + + // Set container to prev so that prev keeps its same value the next time through the loop + container = prev; + } + + // Else if empty, with kids, and (not at root or only one kid) + else if ( + container.threadable == null + && container.child != null + && (container.parent != null + || container.child.next == null)) { + // We have an invalid/expired message with kids. Promote the kids to this level. + ThreadContainer tail; + ThreadContainer kids = container.child; + + // Remove this container and replace with 'kids'. + if (prev == null) + parent.child = kids; + else + prev.next = kids; + + // Make each child's parent be this level's parent -> i.e. promote the children. Make the last child's next point to this container's next + // i.e. splice kids into the list in place of container + for (tail = kids; tail.next != null; tail = tail.next) + tail.parent = container.parent; + + tail.parent = container.parent; + tail.next = container.next; + + // next currently points to the item after the inserted items in the chain - reset that so we process the newly + // promoted items next time round + next = kids; + + // Set container to prev so that prev keeps its same value the next time through the loop + container = prev; + } else if (container.child != null) { + // A real message , with kids + // Iterate over the children + pruneEmptyContainers(container); + } + } + } + + /** + * If any two members of the root set have the same subject, merge them. This is to attempt to accomodate messages without References: headers. + */ + private void gatherSubjects() { + + int count = 0; + + for (ThreadContainer c = root.child; c != null; c = c.next) + count++; + + // TODO verify this will avoid rehashing + HashMap subjectTable = new HashMap((int) (count * 1.2), (float) 0.9); + count = 0; + + for (ThreadContainer c = root.child; c != null; c = c.next) { + Threadable threadable = c.threadable; + + // No threadable? If so, it is a dummy node in the root set. + // Only root set members may be dummies, and they alway have at least 2 kids + // Take the first kid as representative of the subject + if (threadable == null) + threadable = c.child.threadable; + + String subj = threadable.simplifiedSubject(); + + if (subj == null || subj == "") + continue; + + ThreadContainer old = subjectTable.get(subj); + + // Add this container to the table iff: + // - There exists no container with this subject + // - or this is a dummy container and the old one is not - the dummy one is + // more interesting as a root, so put it in the table instead + // - The container in the table has a "Re:" version of this subject, and + // this container has a non-"Re:" version of this subject. The non-"Re:" version + // is the more interesting of the two. + if (old == null + || (c.threadable == null && old.threadable != null) + || (old.threadable != null + && old.threadable.subjectIsReply() + && c.threadable != null + && !c.threadable.subjectIsReply())) { + subjectTable.put(subj, c); + count++; + } + } + + // If the table is empty, we're done + if (count == 0) + return; + + // subjectTable is now populated with one entry for each subject which occurs in the + // root set. Iterate over the root set, and gather together the difference. + ThreadContainer prev, c, rest; + for (prev = null, c = root.child, rest = c.next; + c != null; + prev = c, c = rest, rest = (rest == null ? null : rest.next)) { + Threadable threadable = c.threadable; + + // is it a dummy node? + if (threadable == null) + threadable = c.child.threadable; + + String subj = threadable.simplifiedSubject(); + + // Dont thread together all subjectless messages + if (subj == null || subj == "") + continue; + + ThreadContainer old = subjectTable.get(subj); + + if (old == c) // That's us + continue; + + // We have now found another container in the root set with the same subject + // Remove the "second" message from the root set + if (prev == null) + root.child = c.next; + else + prev.next = c.next; + c.next = null; + + if (old.threadable == null && c.threadable == null) { + // both dummies - merge them + ThreadContainer tail; + for (tail = old.child; + tail != null && tail.next != null; + tail = tail.next); + + tail.next = c.child; + + for (tail = c.child; tail != null; tail = tail.next) + tail.parent = old; + + c.child = null; + } else if ( + old.threadable == null + || (c.threadable != null + && c.threadable.subjectIsReply() + && !old.threadable.subjectIsReply())) { + // Else if old is empty, or c has "Re:" and old does not ==> make this message a child of old + c.parent = old; + c.next = old.child; + old.child = c; + } else { + // else make the old and new messages be children of a new dummy container. + // We create a new container object for old.msg and empty the old container + ThreadContainer newc = new ThreadContainer(); + newc.threadable = old.threadable; + newc.child = old.child; + + for (ThreadContainer tail = newc.child; + tail != null; + tail = tail.next) + tail.parent = newc; + + old.threadable = null; + old.child = null; + + c.parent = old; + newc.parent = old; + + // Old is now a dummy- give it 2 kids , c and newc + old.child = c; + c.next = newc; + } + // We've done a merge, so keep the same prev + c = prev; + } + + subjectTable.clear(); + subjectTable = null; + + } +} + +/** + * A placeholder utility class, used for constructing a tree of Threadables + * Originall implementation by Jamie Zawinski. + * See the Grendel source for more details here + * Threadable objects + * @author Rory Winston + */ +class ThreadContainer { + Threadable threadable; + ThreadContainer parent; + ThreadContainer prev; + ThreadContainer next; + ThreadContainer child; + + /** + * + * @param container + * @return true if child is under self's tree. Detects circular references + */ + boolean findChild(ThreadContainer target) { + if (child == null) + return false; + + else if (child == target) + return true; + else + return child.findChild(target); + } + + // Copy the ThreadContainer tree structure down into the underlying Threadable objects + // (Make the Threadable tree look like the ThreadContainer tree) + void flush() { + if (parent != null && threadable == null) + throw new RuntimeException("no threadable in " + this.toString()); + + parent = null; + + if (threadable != null) + threadable.setChild(child == null ? null : child.threadable); + + if (child != null) { + child.flush(); + child = null; + } + + if (threadable != null) + threadable.setNext(next == null ? null : next.threadable); + + if (next != null) { + next.flush(); + next = null; + } + + threadable = null; + } + + /** + * Reverse the entire set of children + * + */ + void reverseChildren() { + if (child != null) { + ThreadContainer kid, prev, rest; + for (prev = null, kid = child, rest = kid.next; + kid != null; + prev = kid, + kid = rest, + rest = (rest == null ? null : rest.next)) + kid.next = prev; + + child = prev; + + // Do it for the kids + for (kid = child; kid != null; kid = kid.next) + kid.reverseChildren(); + } + } +} diff --git a/org/apache/commons/net/ntp/NTPUDPClient.java b/org/apache/commons/net/ntp/NTPUDPClient.java new file mode 100644 index 0000000..e1dcb57 --- /dev/null +++ b/org/apache/commons/net/ntp/NTPUDPClient.java @@ -0,0 +1,140 @@ +package org.apache.commons.net.ntp; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; + +import org.apache.commons.net.DatagramSocketClient; + +/*** + * The NTPUDPClient class is a UDP implementation of a client for the + * Network Time Protocol (NTP) described in RFC 1305 as well as the + * Simple Network Time Protocol (SNTP) in RFC-2030. To use the class, + * merely open a local datagram socket with open + * and call getTime to retrieve the time. Then call + * close + * to close the connection properly. + * Successive calls to getTime are permitted + * without re-establishing a connection. That is because UDP is a + * connectionless protocol and the Network Time Protocol is stateless. + * + * @author Jason Mathews, MITRE Corp + * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ + ***/ + +public final class NTPUDPClient extends DatagramSocketClient +{ + /*** The default NTP port. It is set to 123 according to RFC 1305. ***/ + public static final int DEFAULT_PORT = 123; + + private int _version = NtpV3Packet.VERSION_3; + + /*** + * Retrieves the time information from the specified server and port and + * returns it. The time is the number of miliiseconds since + * 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. + * This method reads the raw NTP packet and constructs a TimeInfo + * object that allows access to all the fields of the NTP message header. + *

+ * @param host The address of the server. + * @param port The port of the service. + * @return The time value retrieved from the server. + * @exception IOException If an error occurs while retrieving the time. + ***/ + public TimeInfo getTime(InetAddress host, int port) throws IOException + { + // if not connected then open to next available UDP port + if (!isOpen()) + { + open(); + } + + NtpV3Packet message = new NtpV3Impl(); + message.setMode(NtpV3Packet.MODE_CLIENT); + message.setVersion(_version); + DatagramPacket sendPacket = message.getDatagramPacket(); + sendPacket.setAddress(host); + sendPacket.setPort(port); + + NtpV3Packet recMessage = new NtpV3Impl(); + DatagramPacket receivePacket = recMessage.getDatagramPacket(); + + /* + * Must minimize the time between getting the current time, + * timestamping the packet, and sending it out which + * introduces an error in the delay time. + * No extraneous logging and initializations here !!! + */ + TimeStamp now = TimeStamp.getCurrentTime(); + + // Note that if you do not set the transmit time field then originating time + // in server response is all 0's which is "Thu Feb 07 01:28:16 EST 2036". + message.setTransmitTime(now); + + _socket_.send(sendPacket); + _socket_.receive(receivePacket); + + long returnTime = System.currentTimeMillis(); + // create TimeInfo message container but don't pre-compute the details yet + TimeInfo info = new TimeInfo(recMessage, returnTime, false); + + return info; + } + + /*** + * Retrieves the time information from the specified server on the + * default NTP port and returns it. The time is the number of miliiseconds + * since 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. + * This method reads the raw NTP packet and constructs a TimeInfo + * object that allows access to all the fields of the NTP message header. + *

+ * @param host The address of the server. + * @return The time value retrieved from the server. + * @exception IOException If an error occurs while retrieving the time. + ***/ + public TimeInfo getTime(InetAddress host) throws IOException + { + return getTime(host, NtpV3Packet.NTP_PORT); + } + + /*** + * Returns the NTP protocol version number that client sets on request packet + * that is sent to remote host (e.g. 3=NTP v3, 4=NTP v4, etc.) + * + * @return the NTP protocol version number that client sets on request packet. + * @see #setVersion(int) + ***/ + public int getVersion() + { + return _version; + } + + /*** + * Sets the NTP protocol version number that client sets on request packet + * communicate with remote host. + * + * @param version the NTP protocol version number + ***/ + public void setVersion(int version) + { + _version = version; + } + +} diff --git a/org/apache/commons/net/ntp/NtpUtils.java b/org/apache/commons/net/ntp/NtpUtils.java new file mode 100644 index 0000000..ca1fb41 --- /dev/null +++ b/org/apache/commons/net/ntp/NtpUtils.java @@ -0,0 +1,113 @@ +package org.apache.commons.net.ntp; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/*** + * Common NtpUtils Helper class. + * + * @author Jason Mathews, MITRE Corp + * + * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ + */ +public final class NtpUtils { + + /*** + * Returns 32-bit integer address to IPv4 address string "%d.%d.%d.%d" format. + * + * @param address the 32-bit address + * @return the raw IP address in a string format. + */ + public static String getHostAddress(int address) + { + return ((address >>> 24) & 0xFF) + "." + + ((address >>> 16) & 0xFF) + "." + + ((address >>> 8) & 0xFF) + "." + + ((address >>> 0) & 0xFF); + } + + /*** + * Returns NTP packet reference identifier as IP address. + * + * @param packet NTP packet + * @return the packet reference id (as IP address) in "%d.%d.%d.%d" format. + */ + public static String getRefAddress(NtpV3Packet packet) + { + int address = (packet == null) ? 0 : packet.getReferenceId(); + return getHostAddress(address); + } + + /*** + * Get refId as reference clock string (e.g. GPS, WWV, LCL). If string is + * invalid (non-ASCII character) then returns empty string "". + * For details refer to the Comprehensive + * List of Clock Drivers. + * + * @param message + * @return reference clock string if primary NTP server + */ + public static String getReferenceClock(NtpV3Packet message) { + if (message == null) + return ""; + int refId = message.getReferenceId(); + if (refId == 0) + return ""; + StringBuffer buf = new StringBuffer(4); + // start at highest-order byte (0x4c434c00 -> LCL) + for (int shiftBits = 24; shiftBits >= 0; shiftBits -= 8) + { + char c = (char) ((refId >>> shiftBits) & 0xff); + if (c == 0) break; // 0-terminated ASCII string + if (!Character.isLetterOrDigit(c)) + return ""; + buf.append(c); + } + return buf.toString(); + } + + /*** + * Return human-readable name of message mode type (RFC 1305). + * + * @param mode + * @return mode name + */ + public static String getModeName(int mode) + { + switch (mode) { + case NtpV3Packet.MODE_RESERVED: + return "Reserved"; + case NtpV3Packet.MODE_SYMMETRIC_ACTIVE: + return "Symmetric Active"; + case NtpV3Packet.MODE_SYMMETRIC_PASSIVE: + return "Symmetric Passive"; + case NtpV3Packet.MODE_CLIENT: + return "Client"; + case NtpV3Packet.MODE_SERVER: + return "Server"; + case NtpV3Packet.MODE_BROADCAST: + return "Broadcast"; + case NtpV3Packet.MODE_CONTROL_MESSAGE: + return "Control"; + case NtpV3Packet.MODE_PRIVATE: + return "Private"; + default: + return "Unknown"; + } + } + +} diff --git a/org/apache/commons/net/ntp/NtpV3Impl.java b/org/apache/commons/net/ntp/NtpV3Impl.java new file mode 100644 index 0000000..4a8569a --- /dev/null +++ b/org/apache/commons/net/ntp/NtpV3Impl.java @@ -0,0 +1,583 @@ +package org.apache.commons.net.ntp; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.DatagramPacket; + +/*** + * Implementation of NtpV3Packet with methods converting Java objects to/from + * the Network Time Protocol (NTP) data message header format described in RFC-1305. + * + * @author Naz Irizarry, MITRE Corp + * @author Jason Mathews, MITRE Corp + * + * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ + */ +public class NtpV3Impl implements NtpV3Packet +{ + + private static final int MODE_INDEX = 0; + private static final int MODE_SHIFT = 0; + + private static final int VERSION_INDEX = 0; + private static final int VERSION_SHIFT = 3; + + private static final int LI_INDEX = 0; + private static final int LI_SHIFT = 6; + + private static final int STRATUM_INDEX = 1; + private static final int POLL_INDEX = 2; + private static final int PRECISION_INDEX = 3; + + private static final int ROOT_DELAY_INDEX = 4; + private static final int ROOT_DISPERSION_INDEX = 8; + private static final int REFERENCE_ID_INDEX = 12; + + private static final int REFERENCE_TIMESTAMP_INDEX = 16; + private static final int ORIGINATE_TIMESTAMP_INDEX = 24; + private static final int RECEIVE_TIMESTAMP_INDEX = 32; + private static final int TRANSMIT_TIMESTAMP_INDEX = 40; + + private static final int KEY_IDENTIFIER_INDEX = 48; + private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */ + + private byte[] buf = new byte[48]; + + private volatile DatagramPacket dp; + + /** Creates a new instance of NtpV3Impl */ + public NtpV3Impl() + { + } + + /*** + * Returns mode as defined in RFC-1305 which is a 3-bit integer + * whose value is indicated by the MODE_xxx parameters. + * + * @return mode as defined in RFC-1305. + */ + public int getMode() + { + return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7; + } + + /*** + * Return human-readable name of message mode type as described in + * RFC 1305. + * @return mode name as string. + */ + public String getModeName() + { + return NtpUtils.getModeName(getMode()); + } + + /*** + * Set mode as defined in RFC-1305. + * @param mode + */ + public void setMode(int mode) + { + buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7); + } + + /*** + * Returns leap indicator as defined in RFC-1305 which is a two-bit code: + * 0=no warning + * 1=last minute has 61 seconds + * 2=last minute has 59 seconds + * 3=alarm condition (clock not synchronized) + * + * @return leap indicator as defined in RFC-1305. + */ + public int getLeapIndicator() + { + return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3; + } + + /*** + * Set leap indicator as defined in RFC-1305. + * @param li leap indicator. + */ + public void setLeapIndicator(int li) + { + buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT)); + } + + /*** + * Returns poll interval as defined in RFC-1305, which is an eight-bit + * signed integer indicating the maximum interval between successive + * messages, in seconds to the nearest power of two (e.g. value of six + * indicates an interval of 64 seconds. The values that can appear in + * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive. + * + * @return poll interval as defined in RFC-1305. + */ + public int getPoll() + { + return buf[POLL_INDEX]; + } + + /*** + * Set poll interval as defined in RFC-1305. + * + * @param poll poll interval. + */ + public void setPoll(int poll) + { + buf[POLL_INDEX] = (byte) (poll & 0xFF); + } + + /*** + * Returns precision as defined in RFC-1305 encoded as an 8-bit signed + * integer (seconds to nearest power of two). + * Values normally range from -6 to -20. + * + * @return precision as defined in RFC-1305. + */ + public int getPrecision() + { + return buf[PRECISION_INDEX]; + } + + /*** + * Set precision as defined in RFC-1305. + * @param precision + */ + public void setPrecision(int precision) + { + buf[PRECISION_INDEX] = (byte) (precision & 0xFF); + } + + /*** + * Returns NTP version number as defined in RFC-1305. + * + * @return NTP version number. + */ + public int getVersion() + { + return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7; + } + + /*** + * Set NTP version as defined in RFC-1305. + * + * @param version NTP version. + */ + public void setVersion(int version) + { + buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT)); + } + + /*** + * Returns Stratum as defined in RFC-1305, which indicates the stratum level + * of the local clock, with values defined as follows: 0=unspecified, + * 1=primary ref clock, and all others a secondary reference (via NTP). + * + * @return Stratum level as defined in RFC-1305. + */ + public int getStratum() + { + return ui(buf[STRATUM_INDEX]); + } + + /*** + * Set stratum level as defined in RFC-1305. + * + * @param stratum stratum level. + */ + public void setStratum(int stratum) + { + buf[STRATUM_INDEX] = (byte) (stratum & 0xFF); + } + + /*** + * Return root delay as defined in RFC-1305, which is the total roundtrip delay + * to the primary reference source, in seconds. Values can take positive and + * negative values, depending on clock precision and skew. + * + * @return root delay as defined in RFC-1305. + */ + public int getRootDelay() + { + return getInt(ROOT_DELAY_INDEX); + } + + /*** + * Return root delay as defined in RFC-1305 in milliseconds, which is + * the total roundtrip delay to the primary reference source, in + * seconds. Values can take positive and negative values, depending + * on clock precision and skew. + * + * @return root delay in milliseconds + */ + public double getRootDelayInMillisDouble() + { + double l = getRootDelay(); + return l / 65.536; + } + + /*** + * Returns root dispersion as defined in RFC-1305. + * @return root dispersion. + */ + public int getRootDispersion() + { + return getInt(ROOT_DISPERSION_INDEX); + } + + /*** + * Returns root dispersion (as defined in RFC-1305) in milliseconds. + * + * @return root dispersion in milliseconds + */ + public long getRootDispersionInMillis() + { + long l = getRootDispersion(); + return (l * 1000) / 65536L; + } + + /*** + * Returns root dispersion (as defined in RFC-1305) in milliseconds + * as double precision value. + * + * @return root dispersion in milliseconds + */ + public double getRootDispersionInMillisDouble() + { + double l = getRootDispersion(); + return l / 65.536; + } + + /*** + * Set reference clock identifier field with 32-bit unsigned integer value. + * See RFC-1305 for description. + * + * @param refId reference clock identifier. + */ + public void setReferenceId(int refId) + { + for (int i = 3; i >= 0; i--) { + buf[REFERENCE_ID_INDEX + i] = (byte) (refId & 0xff); + refId >>>= 8; // shift right one-byte + } + } + + /*** + * Returns the reference id as defined in RFC-1305, which is + * a 32-bit integer whose value is dependent on several criteria. + * + * @return the reference id as defined in RFC-1305. + */ + public int getReferenceId() + { + return getInt(REFERENCE_ID_INDEX); + } + + /*** + * Returns the reference id string. String cannot be null but + * value is dependent on the version of the NTP spec supported + * and stratum level. Value can be an empty string, clock type string, + * IP address, or a hex string. + * + * @return the reference id string. + */ + public String getReferenceIdString() + { + int version = getVersion(); + int stratum = getStratum(); + if (version == VERSION_3 || version == VERSION_4) { + if (stratum == 0 || stratum == 1) { + return idAsString(); // 4-character ASCII string (e.g. GPS, USNO) + } + // in NTPv4 servers this is latest transmit timestamp of ref source + if (version == VERSION_4) + return idAsHex(); + } + + // Stratum 2 and higher this is a four-octet IPv4 address + // of the primary reference host. + if (stratum >= 2) { + return idAsIPAddress(); + } + return idAsHex(); + } + + /*** + * Returns Reference id as dotted IP address. + * @return refId as IP address string. + */ + private String idAsIPAddress() + { + return ui(buf[REFERENCE_ID_INDEX]) + "." + + ui(buf[REFERENCE_ID_INDEX + 1]) + "." + + ui(buf[REFERENCE_ID_INDEX + 2]) + "." + + ui(buf[REFERENCE_ID_INDEX + 3]); + } + + private String idAsString() + { + StringBuilder id = new StringBuilder(); + for (int i = 0; i <= 3; i++) { + char c = (char) buf[REFERENCE_ID_INDEX + i]; + if (c == 0) break; // 0-terminated string + id.append(c); + } + return id.toString(); + } + + private String idAsHex() + { + return Integer.toHexString(getReferenceId()); + } + + /*** + * Returns the transmit timestamp as defined in RFC-1305. + * + * @return the transmit timestamp as defined in RFC-1305. + * Never returns a null object. + */ + public TimeStamp getTransmitTimeStamp() + { + return getTimestamp(TRANSMIT_TIMESTAMP_INDEX); + } + + /*** + * Set transmit time with NTP timestamp. + * If ts is null then zero time is used. + * + * @param ts NTP timestamp + */ + public void setTransmitTime(TimeStamp ts) + { + setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts); + } + + /*** + * Set originate timestamp given NTP TimeStamp object. + * If ts is null then zero time is used. + * + * @param ts NTP timestamp + */ + public void setOriginateTimeStamp(TimeStamp ts) + { + setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts); + } + + /*** + * Returns the originate time as defined in RFC-1305. + * + * @return the originate time. + * Never returns null. + */ + public TimeStamp getOriginateTimeStamp() + { + return getTimestamp(ORIGINATE_TIMESTAMP_INDEX); + } + + /*** + * Returns the reference time as defined in RFC-1305. + * + * @return the reference time as TimeStamp object. + * Never returns null. + */ + public TimeStamp getReferenceTimeStamp() + { + return getTimestamp(REFERENCE_TIMESTAMP_INDEX); + } + + /*** + * Set Reference time with NTP timestamp. If ts is null + * then zero time is used. + * + * @param ts NTP timestamp + */ + public void setReferenceTime(TimeStamp ts) + { + setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts); + } + + /*** + * Returns receive timestamp as defined in RFC-1305. + * + * @return the receive time. + * Never returns null. + */ + public TimeStamp getReceiveTimeStamp() + { + return getTimestamp(RECEIVE_TIMESTAMP_INDEX); + } + + /*** + * Set receive timestamp given NTP TimeStamp object. + * If ts is null then zero time is used. + * + * @param ts timestamp + */ + public void setReceiveTimeStamp(TimeStamp ts) + { + setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts); + } + + /*** + * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) + * correspond to the protocol used to obtain the timing information. + * + * @return packet type string identifier which in this case is "NTP". + */ + public String getType() + { + return "NTP"; + } + + /*** + * @return 4 bytes as 32-bit int + */ + private int getInt(int index) + { + int i = ui(buf[index]) << 24 | + ui(buf[index + 1]) << 16 | + ui(buf[index + 2]) << 8 | + ui(buf[index + 3]); + + return i; + } + + /*** + * Get NTP Timestamp at specified starting index. + * + * @param index index into data array + * @return TimeStamp object for 64 bits starting at index + */ + private TimeStamp getTimestamp(int index) + { + return new TimeStamp(getLong(index)); + } + + /*** + * Get Long value represented by bits starting at specified index. + * + * @return 8 bytes as 64-bit long + */ + private long getLong(int index) + { + long i = ul(buf[index]) << 56 | + ul(buf[index + 1]) << 48 | + ul(buf[index + 2]) << 40 | + ul(buf[index + 3]) << 32 | + ul(buf[index + 4]) << 24 | + ul(buf[index + 5]) << 16 | + ul(buf[index + 6]) << 8 | + ul(buf[index + 7]); + return i; + } + + /*** + * Sets the NTP timestamp at the given array index. + * + * @param index index into the byte array. + * @param t TimeStamp. + */ + private void setTimestamp(int index, TimeStamp t) + { + long ntpTime = (t == null) ? 0 : t.ntpValue(); + // copy 64-bits from Long value into 8 x 8-bit bytes of array + // one byte at a time shifting 8-bits for each position. + for (int i = 7; i >= 0; i--) { + buf[index + i] = (byte) (ntpTime & 0xFF); + ntpTime >>>= 8; // shift to next byte + } + // buf[index] |= 0x80; // only set if 1900 baseline.... + } + + /*** + * Returns the datagram packet with the NTP details already filled in. + * + * @return a datagram packet. + */ + public synchronized DatagramPacket getDatagramPacket() + { + if (dp == null) { + dp = new DatagramPacket(buf, buf.length); + dp.setPort(NTP_PORT); + } + return dp; + } + + /*** + * Set the contents of this object from source datagram packet. + * + * @param srcDp source DatagramPacket to copy contents from. + */ + public void setDatagramPacket(DatagramPacket srcDp) + { + byte[] incomingBuf = srcDp.getData(); + int len = srcDp.getLength(); + if (len > buf.length) + len = buf.length; + + System.arraycopy(incomingBuf, 0, buf, 0, len); + } + + /*** + * Convert byte to unsigned integer. + * Java only has signed types so we have to do + * more work to get unsigned ops. + * + * @param b + * @return unsigned int value of byte + */ + protected final static int ui(byte b) + { + int i = b & 0xFF; + return i; + } + + /*** + * Convert byte to unsigned long. + * Java only has signed types so we have to do + * more work to get unsigned ops + * + * @param b + * @return unsigned long value of byte + */ + protected final static long ul(byte b) + { + long i = b & 0xFF; + return i; + } + + /*** + * Returns details of NTP packet as a string. + * + * @return details of NTP packet as a string. + */ + @Override + public String toString() + { + return "[" + + "version:" + getVersion() + + ", mode:" + getMode() + + ", poll:" + getPoll() + + ", precision:" + getPrecision() + + ", delay:" + getRootDelay() + + ", dispersion(ms):" + getRootDispersionInMillisDouble() + + ", id:" + getReferenceIdString() + + ", xmitTime:" + getTransmitTimeStamp().toDateString() + + " ]"; + } + +} diff --git a/org/apache/commons/net/ntp/NtpV3Packet.java b/org/apache/commons/net/ntp/NtpV3Packet.java new file mode 100644 index 0000000..52c828b --- /dev/null +++ b/org/apache/commons/net/ntp/NtpV3Packet.java @@ -0,0 +1,236 @@ +package org.apache.commons.net.ntp; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.net.DatagramPacket; + +/** + * Interface for a NtpV3Packet with get/set methods corresponding to the fields + * in the NTP Data Message Header described in RFC 1305. + * + * @author Naz Irizarry, MITRE Corp + * @author Jason Mathews, MITRE Corp + * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ + */ +public interface NtpV3Packet +{ + + /** + * Standard NTP UDP port + */ + public static final int NTP_PORT = 123; + + public static final int LI_NO_WARNING = 0; + public static final int LI_LAST_MINUTE_HAS_61_SECONDS = 1; + public static final int LI_LAST_MINUTE_HAS_59_SECONDS = 2; + public static final int LI_ALARM_CONDITION = 3; + + /* mode options */ + public static final int MODE_RESERVED = 0; + public static final int MODE_SYMMETRIC_ACTIVE = 1; + public static final int MODE_SYMMETRIC_PASSIVE = 2; + public static final int MODE_CLIENT = 3; + public static final int MODE_SERVER = 4; + public static final int MODE_BROADCAST = 5; + public static final int MODE_CONTROL_MESSAGE = 6; + public static final int MODE_PRIVATE = 7; + + public static final int NTP_MINPOLL = 4; // 16 seconds + public static final int NTP_MAXPOLL = 14; // 16284 seconds + + public static final int NTP_MINCLOCK = 1; + public static final int NTP_MAXCLOCK = 10; + + public static final int VERSION_3 = 3; + public static final int VERSION_4 = 4; + + /* possible getType values such that other time-related protocols can + * have its information represented as NTP packets + */ + public static final String TYPE_NTP = "NTP"; // RFC-1305/2030 + public static final String TYPE_ICMP = "ICMP"; // RFC-792 + public static final String TYPE_TIME = "TIME"; // RFC-868 + public static final String TYPE_DAYTIME = "DAYTIME"; // RFC-867 + + /** + * @return a datagram packet with the NTP parts already filled in + */ + public DatagramPacket getDatagramPacket(); + + /** + * Set the contents of this object from the datagram packet + */ + public void setDatagramPacket(DatagramPacket dp); + + /** + * @return leap indicator as defined in RFC-1305 + */ + public int getLeapIndicator(); + + /** + * Set leap indicator. + * @param li - leap indicator code + */ + public void setLeapIndicator(int li); + + /** + * @return mode as defined in RFC-1305 + */ + public int getMode(); + + /** + * @return mode as human readable string; e.g. 3=Client + */ + public String getModeName(); + + /** + * Set mode as defined in RFC-1305 + */ + public void setMode(int mode); + + /** + * @return poll interval as defined in RFC-1305. + * Field range between NTP_MINPOLL and NTP_MAXPOLL. + */ + public int getPoll(); + + /** + * Set poll interval as defined in RFC-1305. + * Field range between NTP_MINPOLL and NTP_MAXPOLL. + */ + public void setPoll(int poll); + + /** + * @return precision as defined in RFC-1305 + */ + public int getPrecision(); + + /** + * @return root delay as defined in RFC-1305 + */ + public int getRootDelay(); + + /** + * @return root delay in milliseconds + */ + public double getRootDelayInMillisDouble(); + + /** + * @return root dispersion as defined in RFC-1305 + */ + public int getRootDispersion(); + + /** + * @return root dispersion in milliseconds + */ + public long getRootDispersionInMillis(); + + /** + * @return root dispersion in milliseconds + */ + public double getRootDispersionInMillisDouble(); + + /** + * @return version as defined in RFC-1305 + */ + public int getVersion(); + + /** + * Set version as defined in RFC-1305 + */ + public void setVersion(int mode); + + /** + * @return stratum as defined in RFC-1305 + */ + public int getStratum(); + + /** + * Set stratum as defined in RFC-1305 + */ + public void setStratum(int stratum); + + /** + * @return the reference id string + */ + public String getReferenceIdString(); + + /** + * @return the reference id (32-bit code) as defined in RFC-1305 + */ + public int getReferenceId(); + + /** + * Set reference clock identifier field. + * @param refId + */ + public void setReferenceId(int refId); + + /** + * @return the transmit timestamp as defined in RFC-1305 + */ + public TimeStamp getTransmitTimeStamp(); + + /** + * @return the reference time as defined in RFC-1305 + */ + public TimeStamp getReferenceTimeStamp(); + + /** + * @return the originate time as defined in RFC-1305 + */ + public TimeStamp getOriginateTimeStamp(); + + /** + * @return the receive time as defined in RFC-1305 + */ + public TimeStamp getReceiveTimeStamp(); + + /** + * Set the transmit timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setTransmitTime(TimeStamp ts); + + /** + * Set the reference timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setReferenceTime(TimeStamp ts); + + /** + * Set originate timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setOriginateTimeStamp(TimeStamp ts); + + /** + * Set receive timestamp given NTP TimeStamp object. + * @param ts - timestamp + */ + public void setReceiveTimeStamp(TimeStamp ts); + + /** + * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) + * correspond to the protocol used to obtain the timing information. + * + * @return packet type string identifier + */ + public String getType(); + +} diff --git a/org/apache/commons/net/ntp/TimeInfo.java b/org/apache/commons/net/ntp/TimeInfo.java new file mode 100644 index 0000000..4ef17fd --- /dev/null +++ b/org/apache/commons/net/ntp/TimeInfo.java @@ -0,0 +1,295 @@ +package org.apache.commons.net.ntp; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.ArrayList; +import java.util.List; + +/** + * Wrapper class to network time packet messages (NTP, etc) that computes + * related timing info and stats. + * + * @author Jason Mathews, MITRE Corp + * + * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ + */ +public class TimeInfo { + + private NtpV3Packet _message; + private List _comments; + private Long _delay; + private Long _offset; + + /** + * time at which time message packet was received by local machine + */ + private long _returnTime; + + /** + * flag indicating that the TimeInfo details was processed and delay/offset were computed + */ + private boolean _detailsComputed; + + /** + * Create TimeInfo object with raw packet message and destination time received. + * + * @param message NTP message packet + * @param returnTime destination receive time + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet message, long returnTime) { + this(message, returnTime, null, true); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * + * @param message NTP message packet + * @param returnTime destination receive time + * @param comments List of errors/warnings identified during processing + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet message, long returnTime, List comments) + { + this(message, returnTime, comments, true); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * Auto-computes details if computeDetails flag set otherwise this is delayed + * until computeDetails() is called. Delayed computation is for fast + * intialization when sub-millisecond timing is needed. + * + * @param msgPacket NTP message packet + * @param returnTime destination receive time + * @param doComputeDetails flag to pre-compute delay/offset values + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet msgPacket, long returnTime, boolean doComputeDetails) + { + this(msgPacket, returnTime, null, doComputeDetails); + } + + /** + * Create TimeInfo object with raw packet message and destination time received. + * Auto-computes details if computeDetails flag set otherwise this is delayed + * until computeDetails() is called. Delayed computation is for fast + * intialization when sub-millisecond timing is needed. + * + * @param message NTP message packet + * @param returnTime destination receive time + * @param comments list of comments used to store errors/warnings with message + * @param doComputeDetails flag to pre-compute delay/offset values + * @throws IllegalArgumentException if message is null + */ + public TimeInfo(NtpV3Packet message, long returnTime, List comments, + boolean doComputeDetails) + { + if (message == null) + throw new IllegalArgumentException("message cannot be null"); + this._returnTime = returnTime; + this._message = message; + this._comments = comments; + if (doComputeDetails) + computeDetails(); + } + + /** + * Add comment (error/warning) to list of comments associated + * with processing of NTP parameters. If comment list not create + * then one will be created. + * + * @param comment + */ + public void addComment(String comment) + { + if (_comments == null) { + _comments = new ArrayList(); + } + _comments.add(comment); + } + + /** + * Compute and validate details of the NTP message packet. Computed + * fields include the offset and delay. + */ + public void computeDetails() + { + if (_detailsComputed) { + return; // details already computed - do nothing + } + _detailsComputed = true; + if (_comments == null) { + _comments = new ArrayList(); + } + + TimeStamp origNtpTime = _message.getOriginateTimeStamp(); + long origTime = origNtpTime.getTime(); + + // Receive Time is time request received by server (t2) + TimeStamp rcvNtpTime = _message.getReceiveTimeStamp(); + long rcvTime = rcvNtpTime.getTime(); + + // Transmit time is time reply sent by server (t3) + TimeStamp xmitNtpTime = _message.getTransmitTimeStamp(); + long xmitTime = xmitNtpTime.getTime(); + + /* + * Round-trip network delay and local clock offset (or time drift) is calculated + * according to this standard NTP equation: + * + * LocalClockOffset = ((ReceiveTimestamp - OriginateTimestamp) + + * (TransmitTimestamp - DestinationTimestamp)) / 2 + * + * equations from RFC-1305 (NTPv3) + * roundtrip delay = (t4 - t1) - (t3 - t2) + * local clock offset = ((t2 - t1) + (t3 - t4)) / 2 + * + * It takes into account network delays and assumes that they are symmetrical. + * + * Note the typo in SNTP RFCs 1769/2030 which state that the delay + * is (T4 - T1) - (T2 - T3) with the "T2" and "T3" switched. + */ + if (origNtpTime.ntpValue() == 0) + { + // without originate time cannot determine when packet went out + // might be via a broadcast NTP packet... + if (xmitNtpTime.ntpValue() != 0) + { + _offset = Long.valueOf(xmitTime - _returnTime); + _comments.add("Error: zero orig time -- cannot compute delay"); + } else + _comments.add("Error: zero orig time -- cannot compute delay/offset"); + } else if (rcvNtpTime.ntpValue() == 0 || xmitNtpTime.ntpValue() == 0) + { + _comments.add("Warning: zero rcvNtpTime or xmitNtpTime"); + // assert destTime >= origTime since network delay cannot be negative + if (origTime > _returnTime) + _comments.add("Error: OrigTime > DestRcvTime"); + else + { + // without receive or xmit time cannot figure out processing time + // so delay is simply the network travel time + _delay = Long.valueOf(_returnTime - origTime); + } + // TODO: is offset still valid if rcvNtpTime=0 || xmitNtpTime=0 ??? + // Could always hash origNtpTime (sendTime) but if host doesn't set it + // then it's an malformed ntp host anyway and we don't care? + // If server is in broadcast mode then we never send out a query in first place... + if (rcvNtpTime.ntpValue() != 0) + { + // xmitTime is 0 just use rcv time + _offset = Long.valueOf(rcvTime - origTime); + } else if (xmitNtpTime.ntpValue() != 0) + { + // rcvTime is 0 just use xmitTime time + _offset = Long.valueOf(xmitTime - _returnTime); + } + } else + { + long delayValue = _returnTime - origTime; + // assert xmitTime >= rcvTime: difference typically < 1ms + if (xmitTime < rcvTime) + { + // server cannot send out a packet before receiving it... + _comments.add("Error: xmitTime < rcvTime"); // time-travel not allowed + } else + { + // subtract processing time from round-trip network delay + long delta = xmitTime - rcvTime; + // in normal cases the processing delta is less than + // the total roundtrip network travel time. + if (delta <= delayValue) + { + delayValue -= delta; // delay = (t4 - t1) - (t3 - t2) + } else + { + // if delta - delayValue == 1 ms then it's a round-off error + // e.g. delay=3ms, processing=4ms + if (delta - delayValue == 1) + { + // delayValue == 0 -> local clock saw no tick change but destination clock did + if (delayValue != 0) + { + _comments.add("Info: processing time > total network time by 1 ms -> assume zero delay"); + delayValue = 0; + } + } else + _comments.add("Warning: processing time > total network time"); + } + } + _delay = Long.valueOf(delayValue); + if (origTime > _returnTime) // assert destTime >= origTime + _comments.add("Error: OrigTime > DestRcvTime"); + + _offset = Long.valueOf(((rcvTime - origTime) + (xmitTime - _returnTime)) / 2); + } + } + + /** + * Return list of comments (if any) during processing of NTP packet. + * + * @return List or null if not yet computed + */ + public List getComments() + { + return _comments; + } + + /** + * Get round-trip network delay. If null then could not compute the delay. + * + * @return Long or null if delay not available. + */ + public Long getDelay() + { + return _delay; + } + + /** + * Get clock offset needed to adjust local clock to match remote clock. If null then could not + * compute the offset. + * + * @return Long or null if offset not available. + */ + public Long getOffset() + { + return _offset; + } + + /** + * Returns NTP message packet. + * + * @return NTP message packet. + */ + public NtpV3Packet getMessage() + { + return _message; + } + + /** + * Returns time at which time message packet was received by local machine. + * + * @return packet return time. + */ + public long getReturnTime() + { + return _returnTime; + } + +} diff --git a/org/apache/commons/net/ntp/TimeStamp.java b/org/apache/commons/net/ntp/TimeStamp.java new file mode 100644 index 0000000..4cbe26f --- /dev/null +++ b/org/apache/commons/net/ntp/TimeStamp.java @@ -0,0 +1,490 @@ +package org.apache.commons.net.ntp; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +import java.lang.ref.SoftReference; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/*** + * TimeStamp class represents the Network Time Protocol (NTP) timestamp + * as defined in RFC-1305 and SNTP (RFC-2030). It is represented as a + * 64-bit unsigned fixed-point number in seconds relative to 0-hour on 1-January-1900. + * The 32-bit low-order bits are the fractional seconds whose precision is + * about 200 picoseconds. Assumes overflow date when date passes MAX_LONG + * and reverts back to 0 is 2036 and not 1900. Test for most significant + * bit: if MSB=0 then 2036 basis is used otherwise 1900 if MSB=1. + *

+ * Methods exist to convert NTP timestamps to and from the equivalent Java date + * representation, which is the number of milliseconds since the standard base + * time known as "the epoch", namely January 1, 1970, 00:00:00 GMT. + *

+ * + * @author Jason Mathews, MITRE Corp + * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ + * @see java.util.Date + */ +public class TimeStamp implements java.io.Serializable, Comparable // TODO add comparable type? +{ + + /** + * baseline NTP time if bit-0=0 -> 7-Feb-2036 @ 06:28:16 UTC + */ + protected static final long msb0baseTime = 2085978496000L; + + /** + * baseline NTP time if bit-0=1 -> 1-Jan-1900 @ 01:00:00 UTC + */ + protected static final long msb1baseTime = -2208988800000L; + + /** + * Default NTP date string format. E.g. Fri, Sep 12 2003 21:06:23.860. + * See java.text.SimpleDateFormat for code descriptions. + */ + public final static String NTP_DATE_FORMAT = "EEE, MMM dd yyyy HH:mm:ss.SSS"; + + /* + * Caches for the DateFormatters used by various toString methods. + */ + private static SoftReference simpleFormatter = null; + private static SoftReference utcFormatter = null; + + /** + * NTP timestamp value: 64-bit unsigned fixed-point number as defined in RFC-1305 + * with high-order 32 bits the seconds field and the low-order 32-bits the + * fractional field. + */ + private long ntpTime; + + private static final long serialVersionUID = 8139806907588338737L; + + // initialization of static time bases + /* + static { + TimeZone utcZone = TimeZone.getTimeZone("UTC"); + Calendar calendar = Calendar.getInstance(utcZone); + calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0); + calendar.set(Calendar.MILLISECOND, 0); + msb1baseTime = calendar.getTime().getTime(); + calendar.set(2036, Calendar.FEBRUARY, 7, 6, 28, 16); + calendar.set(Calendar.MILLISECOND, 0); + msb0baseTime = calendar.getTime().getTime(); + } + */ + + /*** + * Constructs a newly allocated NTP timestamp object + * that represents the native 64-bit long argument. + */ + public TimeStamp(long ntpTime) + { + this.ntpTime = ntpTime; + } + + /*** + * Constructs a newly allocated NTP timestamp object + * that represents the value represented by the string + * in hexdecimal form (e.g. "c1a089bd.fc904f6d"). + * + * @throws NumberFormatException - if the string does not contain a parsable timestamp. + */ + public TimeStamp(String s) throws NumberFormatException + { + ntpTime = decodeNtpHexString(s); + } + + /*** + * Constructs a newly allocated NTP timestamp object + * that represents the Java Date argument. + * + * @param d - the Date to be represented by the Timestamp object. + */ + public TimeStamp(Date d) + { + ntpTime = (d == null) ? 0 : toNtpTime(d.getTime()); + } + + /*** + * Returns the value of this Timestamp as a long value. + * + * @return the 64-bit long value represented by this object. + */ + public long ntpValue() + { + return ntpTime; + } + + /*** + * Returns high-order 32-bits representing the seconds of this NTP timestamp. + * + * @return seconds represented by this NTP timestamp. + */ + public long getSeconds() + { + return (ntpTime >>> 32) & 0xffffffffL; + } + + /*** + * Returns low-order 32-bits representing the fractional seconds. + * + * @return fractional seconds represented by this NTP timestamp. + */ + public long getFraction() + { + return ntpTime & 0xffffffffL; + } + + /*** + * Convert NTP timestamp to Java standard time. + * + * @return NTP Timestamp in Java time + */ + public long getTime() + { + return getTime(ntpTime); + } + + /*** + * Convert NTP timestamp to Java Date object. + * + * @return NTP Timestamp in Java Date + */ + public Date getDate() + { + long time = getTime(ntpTime); + return new Date(time); + } + + /*** + * Convert 64-bit NTP timestamp to Java standard time. + * + * Note that java time (milliseconds) by definition has less precision + * then NTP time (picoseconds) so converting NTP timestamp to java time and back + * to NTP timestamp loses precision. For example, Tue, Dec 17 2002 09:07:24.810 EST + * is represented by a single Java-based time value of f22cd1fc8a, but its + * NTP equivalent are all values ranging from c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c. + * + * @param ntpTimeValue + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT + * represented by this NTP timestamp value. + */ + public static long getTime(long ntpTimeValue) + { + long seconds = (ntpTimeValue >>> 32) & 0xffffffffL; // high-order 32-bits + long fraction = ntpTimeValue & 0xffffffffL; // low-order 32-bits + + // Use round-off on fractional part to preserve going to lower precision + fraction = Math.round(1000D * fraction / 0x100000000L); + + /* + * If the most significant bit (MSB) on the seconds field is set we use + * a different time base. The following text is a quote from RFC-2030 (SNTP v4): + * + * If bit 0 is set, the UTC time is in the range 1968-2036 and UTC time + * is reckoned from 0h 0m 0s UTC on 1 January 1900. If bit 0 is not set, + * the time is in the range 2036-2104 and UTC time is reckoned from + * 6h 28m 16s UTC on 7 February 2036. + */ + long msb = seconds & 0x80000000L; + if (msb == 0) { + // use base: 7-Feb-2036 @ 06:28:16 UTC + return msb0baseTime + (seconds * 1000) + fraction; + } else { + // use base: 1-Jan-1900 @ 01:00:00 UTC + return msb1baseTime + (seconds * 1000) + fraction; + } + } + + /*** + * Helper method to convert Java time to NTP timestamp object. + * Note that Java time (milliseconds) by definition has less precision + * then NTP time (picoseconds) so converting Ntptime to Javatime and back + * to Ntptime loses precision. For example, Tue, Dec 17 2002 09:07:24.810 + * is represented by a single Java-based time value of f22cd1fc8a, but its + * NTP equivalent are all values from c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c. + * @param date the milliseconds since January 1, 1970, 00:00:00 GMT. + * @return NTP timestamp object at the specified date. + */ + public static TimeStamp getNtpTime(long date) + { + return new TimeStamp(toNtpTime(date)); + } + + /*** + * Constructs a NTP timestamp object and initializes it so that + * it represents the time at which it was allocated, measured to the + * nearest millisecond. + * @return NTP timestamp object set to the current time. + * @see java.lang.System#currentTimeMillis() + */ + public static TimeStamp getCurrentTime() + { + return getNtpTime(System.currentTimeMillis()); + } + + /*** + * Convert NTP timestamp hexstring (e.g. "c1a089bd.fc904f6d") to the NTP + * 64-bit unsigned fixed-point number. + * + * @return NTP 64-bit timestamp value. + * @throws NumberFormatException - if the string does not contain a parsable timestamp. + */ + protected static long decodeNtpHexString(String s) + throws NumberFormatException + { + if (s == null) { + throw new NumberFormatException("null"); + } + int ind = s.indexOf('.'); + if (ind == -1) { + if (s.length() == 0) return 0; + return Long.parseLong(s, 16) << 32; // no decimal + } + + return Long.parseLong(s.substring(0, ind), 16) << 32 | + Long.parseLong(s.substring(ind + 1), 16); + } + + /*** + * Parses the string argument as a NTP hexidecimal timestamp representation string + * (e.g. "c1a089bd.fc904f6d"). + * + * @param s - hexstring. + * @return the Timestamp represented by the argument in hexidecimal. + * @throws NumberFormatException - if the string does not contain a parsable timestamp. + */ + public static TimeStamp parseNtpString(String s) + throws NumberFormatException + { + return new TimeStamp(decodeNtpHexString(s)); + } + + /*** + * Converts Java time to 64-bit NTP time representation. + * + * @param t Java time + * @return NTP timestamp representation of Java time value. + */ + protected static long toNtpTime(long t) + { + boolean useBase1 = t < msb0baseTime; // time < Feb-2036 + long baseTime; + if (useBase1) { + baseTime = t - msb1baseTime; // dates <= Feb-2036 + } else { + // if base0 needed for dates >= Feb-2036 + baseTime = t - msb0baseTime; + } + + long seconds = baseTime / 1000; + long fraction = ((baseTime % 1000) * 0x100000000L) / 1000; + + if (useBase1) { + seconds |= 0x80000000L; // set high-order bit if msb1baseTime 1900 used + } + + long time = seconds << 32 | fraction; + return time; + } + + /*** + * Computes a hashcode for this Timestamp. The result is the exclusive + * OR of the two halves of the primitive long value + * represented by this TimeStamp object. That is, the hashcode + * is the value of the expression: + *
+     * (int)(this.ntpValue()^(this.ntpValue() >>> 32))
+     * 
+ * + * @return a hash code value for this object. + */ + @Override + public int hashCode() + { + return (int) (ntpTime ^ (ntpTime >>> 32)); + } + + /*** + * Compares this object against the specified object. + * The result is true if and only if the argument is + * not null and is a Long object that + * contains the same long value as this object. + * + * @param obj the object to compare with. + * @return true if the objects are the same; + * false otherwise. + */ + @Override + public boolean equals(Object obj) + { + if (obj instanceof TimeStamp) { + return ntpTime == ((TimeStamp) obj).ntpValue(); + } + return false; + } + + /*** + * Converts this TimeStamp object to a String. + * The NTP timestamp 64-bit long value is represented as hex string with + * seconds separated by fractional seconds by a decimal point; + * e.g. c1a089bd.fc904f6d <=> Tue, Dec 10 2002 10:41:49.986 + * + * @return NTP timestamp 64-bit long value as hex string with seconds + * separated by fractional seconds. + */ + @Override + public String toString() + { + return toString(ntpTime); + } + + /*** + * Left-pad 8-character hex string with 0's + * + * @param buf - StringBuffer which is appended with leading 0's. + * @param l - a long. + */ + private static void appendHexString(StringBuffer buf, long l) + { + String s = Long.toHexString(l); + for (int i = s.length(); i < 8; i++) + buf.append('0'); + buf.append(s); + } + + /*** + * Converts 64-bit NTP timestamp value to a String. + * The NTP timestamp value is represented as hex string with + * seconds separated by fractional seconds by a decimal point; + * e.g. c1a089bd.fc904f6d <=> Tue, Dec 10 2002 10:41:49.986 + * + * @return NTP timestamp 64-bit long value as hex string with seconds + * separated by fractional seconds. + */ + public static String toString(long ntpTime) + { + StringBuffer buf = new StringBuffer(); + // high-order second bits (32..63) as hexstring + appendHexString(buf, (ntpTime >>> 32) & 0xffffffffL); + + // low-order fractional seconds bits (0..31) as hexstring + buf.append('.'); + appendHexString(buf, ntpTime & 0xffffffffL); + + return buf.toString(); + } + + /*** + * Converts this TimeStamp object to a String + * of the form: + *
+     * EEE, MMM dd yyyy HH:mm:ss.SSS
+ * See java.text.SimpleDataFormat for code descriptions. + * + * @return a string representation of this date. + */ + public String toDateString() + { + DateFormat formatter = null; + if (simpleFormatter != null) { + formatter = simpleFormatter.get(); + } + if (formatter == null) { + // No cache yet, or cached formatter GC'd + formatter = new SimpleDateFormat(NTP_DATE_FORMAT, Locale.US); + formatter.setTimeZone(TimeZone.getDefault()); + simpleFormatter = new SoftReference(formatter); + } + Date ntpDate = getDate(); + synchronized (formatter) { + return formatter.format(ntpDate); + } + } + + /*** + * Converts this TimeStamp object to a String + * of the form: + *
+     * EEE, MMM dd yyyy HH:mm:ss.SSS UTC
+ * See java.text.SimpleDataFormat for code descriptions. + * + * @return a string representation of this date in UTC. + */ + public String toUTCString() + { + DateFormat formatter = null; + if (utcFormatter != null) + formatter = utcFormatter.get(); + if (formatter == null) { + // No cache yet, or cached formatter GC'd + formatter = new SimpleDateFormat(NTP_DATE_FORMAT + " 'UTC'", + Locale.US); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + utcFormatter = new SoftReference(formatter); + } + Date ntpDate = getDate(); + synchronized (formatter) { + return formatter.format(ntpDate); + } + } + + /*** + * Compares two Timestamps numerically. + * + * @param anotherTimeStamp - the TimeStamp to be compared. + * @return the value 0 if the argument TimeStamp is equal to + * this TimeStamp; a value less than 0 if this TimeStamp + * is numerically less than the TimeStamp argument; and a + * value greater than 0 if this TimeStamp is + * numerically greater than the TimeStamp argument + * (signed comparison). + */ + public int compareTo(TimeStamp anotherTimeStamp) + { + long thisVal = this.ntpTime; + long anotherVal = anotherTimeStamp.ntpTime; + return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1)); + } + + /*** + * Compares this TimeStamp to another Object. If the Object is a TimeStamp, + * this function behaves like compareTo(TimeStamp). Otherwise, + * it throws a ClassCastException (as TimeStamps are comparable + * only to other TimeStamps). + * + * @param o the Object to be compared. + * @return the value 0 if the argument is a TimeStamp + * numerically equal to this TimeStamp; a value less than + * 0 if the argument is a TimeStamp numerically + * greater than this TimeStamp; and a value greater than + * 0 if the argument is a TimeStamp numerically + * less than this TimeStamp. + * @exception ClassCastException if the argument is not a + * TimeStamp. + * @see java.lang.Comparable + */ + public int compareTo(Object o) + { + return compareTo((TimeStamp) o); + } + +} diff --git a/org/apache/commons/net/pop3/POP3.java b/org/apache/commons/net/pop3/POP3.java new file mode 100644 index 0000000..80033ab --- /dev/null +++ b/org/apache/commons/net/pop3/POP3.java @@ -0,0 +1,358 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.pop3; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Enumeration; +import java.util.Vector; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ProtocolCommandListener; +import org.apache.commons.net.ProtocolCommandSupport; +import org.apache.commons.net.SocketClient; + +/*** + * The POP3 class is not meant to be used by itself and is provided + * only so that you may easily implement your own POP3 client if + * you so desire. If you have no need to perform your own implementation, + * you should use {@link org.apache.commons.net.pop3.POP3Client}. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @see POP3Client + * @see org.apache.commons.net.MalformedServerReplyException + ***/ + +public class POP3 extends SocketClient +{ + /*** The default POP3 port. Set to 110 according to RFC 1288. ***/ + public static final int DEFAULT_PORT = 110; + /*** + * A constant representing the state where the client is not yet connected + * to a POP3 server. + ***/ + public static final int DISCONNECTED_STATE = -1; + /*** A constant representing the POP3 authorization state. ***/ + public static final int AUTHORIZATION_STATE = 0; + /*** A constant representing the POP3 transaction state. ***/ + public static final int TRANSACTION_STATE = 1; + /*** A constant representing the POP3 update state. ***/ + public static final int UPDATE_STATE = 2; + + static final String _OK = "+OK"; + static final String _ERROR = "-ERR"; + + // We have to ensure that the protocol communication is in ASCII + // but we use ISO-8859-1 just in case 8-bit characters cross + // the wire. + private static final String __DEFAULT_ENCODING = "ISO-8859-1"; + + private int __popState; + private BufferedWriter __writer; + private StringBuffer __commandBuffer; + + BufferedReader _reader; + int _replyCode; + String _lastReplyLine; + Vector _replyLines; + + /*** + * A ProtocolCommandSupport object used to manage the registering of + * ProtocolCommandListeners and te firing of ProtocolCommandEvents. + ***/ + protected ProtocolCommandSupport _commandSupport_; + + /*** + * The default POP3Client constructor. Initializes the state + * to DISCONNECTED_STATE. + ***/ + public POP3() + { + setDefaultPort(DEFAULT_PORT); + __commandBuffer = new StringBuffer(); + __popState = DISCONNECTED_STATE; + _reader = null; + __writer = null; + _replyLines = new Vector(); + _commandSupport_ = new ProtocolCommandSupport(this); + } + + private void __getReply() throws IOException + { + String line; + + _replyLines.setSize(0); + line = _reader.readLine(); + + if (line == null) + throw new EOFException("Connection closed without indication."); + + if (line.startsWith(_OK)) + _replyCode = POP3Reply.OK; + else if (line.startsWith(_ERROR)) + _replyCode = POP3Reply.ERROR; + else + throw new + MalformedServerReplyException( + "Received invalid POP3 protocol response from server."); + + _replyLines.addElement(line); + _lastReplyLine = line; + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); + } + + + /*** + * Performs connection initialization and sets state to + * AUTHORIZATION_STATE . + ***/ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + _reader = + new BufferedReader(new InputStreamReader(_input_, + __DEFAULT_ENCODING)); + __writer = + new BufferedWriter(new OutputStreamWriter(_output_, + __DEFAULT_ENCODING)); + __getReply(); + setState(AUTHORIZATION_STATE); + } + + + /*** + * Adds a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.addProtocolCommandListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandistener(ProtocolCommandListener listener) + { + _commandSupport_.removeProtocolCommandListener(listener); + } + + + /*** + * Sets POP3 client state. This must be one of the + * _STATE constants. + *

+ * @param state The new state. + ***/ + public void setState(int state) + { + __popState = state; + } + + + /*** + * Returns the current POP3 client state. + *

+ * @return The current POP3 client state. + ***/ + public int getState() + { + return __popState; + } + + + /*** + * Retrieves the additional lines of a multi-line server reply. + ***/ + public void getAdditionalReply() throws IOException + { + String line; + + line = _reader.readLine(); + while (line != null) + { + _replyLines.addElement(line); + if (line.equals(".")) + break; + line = _reader.readLine(); + } + } + + + /*** + * Disconnects the client from the server, and sets the state to + * DISCONNECTED_STATE . The reply text information + * from the last issued command is voided to allow garbage collection + * of the memory used to store that information. + *

+ * @exception IOException If there is an error in disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + _reader = null; + __writer = null; + _lastReplyLine = null; + _replyLines.setSize(0); + setState(DISCONNECTED_STATE); + } + + + /*** + * Sends a command an arguments to the server and returns the reply code. + *

+ * @param command The POP3 command to send. + * @param args The command arguments. + * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). + ***/ + public int sendCommand(String command, String args) throws IOException + { + String message; + + __commandBuffer.setLength(0); + __commandBuffer.append(command); + + if (args != null) + { + __commandBuffer.append(' '); + __commandBuffer.append(args); + } + __commandBuffer.append(SocketClient.NETASCII_EOL); + + __writer.write(message = __commandBuffer.toString()); + __writer.flush(); + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireCommandSent(command, message); + + __getReply(); + return _replyCode; + } + + /*** + * Sends a command with no arguments to the server and returns the + * reply code. + *

+ * @param command The POP3 command to send. + * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). + ***/ + public int sendCommand(String command) throws IOException + { + return sendCommand(command, null); + } + + /*** + * Sends a command an arguments to the server and returns the reply code. + *

+ * @param command The POP3 command to send + * (one of the POP3Command constants). + * @param args The command arguments. + * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). + ***/ + public int sendCommand(int command, String args) throws IOException + { + return sendCommand(POP3Command._commands[command], args); + } + + /*** + * Sends a command with no arguments to the server and returns the + * reply code. + *

+ * @param command The POP3 command to send + * (one of the POP3Command constants). + * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). + ***/ + public int sendCommand(int command) throws IOException + { + return sendCommand(POP3Command._commands[command], null); + } + + + /*** + * Returns an array of lines received as a reply to the last command + * sent to the server. The lines have end of lines truncated. If + * the reply is a single line, but its format ndicates it should be + * a multiline reply, then you must call + * {@link #getAdditionalReply getAdditionalReply() } to + * fetch the rest of the reply, and then call getReplyStrings + * again. You only have to worry about this if you are implementing + * your own client using the {@link #sendCommand sendCommand } methods. + *

+ * @return The last server response. + ***/ + public String[] getReplyStrings() + { + String[] lines; + lines = new String[_replyLines.size()]; + _replyLines.copyInto(lines); + return lines; + } + + /*** + * Returns the reply to the last command sent to the server. + * The value is a single string containing all the reply lines including + * newlines. If the reply is a single line, but its format ndicates it + * should be a multiline reply, then you must call + * {@link #getAdditionalReply getAdditionalReply() } to + * fetch the rest of the reply, and then call getReplyString + * again. You only have to worry about this if you are implementing + * your own client using the {@link #sendCommand sendCommand } methods. + *

+ * @return The last server response. + ***/ + public String getReplyString() + { + Enumeration en; + StringBuffer buffer = new StringBuffer(256); + + en = _replyLines.elements(); + while (en.hasMoreElements()) + { + buffer.append(en.nextElement()); + buffer.append(SocketClient.NETASCII_EOL); + } + + return buffer.toString(); + } + +} + diff --git a/org/apache/commons/net/pop3/POP3Client.java b/org/apache/commons/net/pop3/POP3Client.java new file mode 100644 index 0000000..c5e9a96 --- /dev/null +++ b/org/apache/commons/net/pop3/POP3Client.java @@ -0,0 +1,552 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.pop3; + +import java.io.IOException; +import java.io.Reader; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Enumeration; +import java.util.StringTokenizer; + +import org.apache.commons.net.io.DotTerminatedMessageReader; + +/*** + * The POP3Client class implements the client side of the Internet POP3 + * Protocol defined in RFC 1939. All commands are supported, including + * the APOP command which requires MD5 encryption. See RFC 1939 for + * more details on the POP3 protocol. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @see POP3MessageInfo + * @see org.apache.commons.net.io.DotTerminatedMessageReader + * @see org.apache.commons.net.MalformedServerReplyException + ***/ + +public class POP3Client extends POP3 +{ + + private static POP3MessageInfo __parseStatus(String line) + { + int num, size; + StringTokenizer tokenizer; + + tokenizer = new StringTokenizer(line); + + if (!tokenizer.hasMoreElements()) + return null; + + num = size = 0; + + try + { + num = Integer.parseInt(tokenizer.nextToken()); + + if (!tokenizer.hasMoreElements()) + return null; + + size = Integer.parseInt(tokenizer.nextToken()); + } + catch (NumberFormatException e) + { + return null; + } + + return new POP3MessageInfo(num, size); + } + + private static POP3MessageInfo __parseUID(String line) + { + int num; + StringTokenizer tokenizer; + + tokenizer = new StringTokenizer(line); + + if (!tokenizer.hasMoreElements()) + return null; + + num = 0; + + try + { + num = Integer.parseInt(tokenizer.nextToken()); + + if (!tokenizer.hasMoreElements()) + return null; + + line = tokenizer.nextToken(); + } + catch (NumberFormatException e) + { + return null; + } + + return new POP3MessageInfo(num, line); + } + + /*** + * Login to the POP3 server with the given username and password. You + * must first connect to the server with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before attempting to login. A login attempt is only valid if + * the client is in the + * {@link org.apache.commons.net.pop3.POP3#AUTHORIZATION_STATE AUTHORIZATION_STATE } + * . After logging in, the client enters the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . + *

+ * @param username The account name being logged in to. + * @param password The plain text password of the account. + * @return True if the login attempt was successful, false if not. + * @exception IOException If a network I/O error occurs in the process of + * logging in. + ***/ + public boolean login(String username, String password) throws IOException + { + if (getState() != AUTHORIZATION_STATE) + return false; + + if (sendCommand(POP3Command.USER, username) != POP3Reply.OK) + return false; + + if (sendCommand(POP3Command.PASS, password) != POP3Reply.OK) + return false; + + setState(TRANSACTION_STATE); + + return true; + } + + + /*** + * Login to the POP3 server with the given username and authentication + * information. Use this method when connecting to a server requiring + * authentication using the APOP command. Because the timestamp + * produced in the greeting banner varies from server to server, it is + * not possible to consistently extract the information. Therefore, + * after connecting to the server, you must call + * {@link org.apache.commons.net.pop3.POP3#getReplyString getReplyString } + * and parse out the timestamp information yourself. + *

+ * You must first connect to the server with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before attempting to login. A login attempt is only valid if + * the client is in the + * {@link org.apache.commons.net.pop3.POP3#AUTHORIZATION_STATE AUTHORIZATION_STATE } + * . After logging in, the client enters the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . After connecting, you must parse out the + * server specific information to use as a timestamp, and pass that + * information to this method. The secret is a shared secret known + * to you and the server. See RFC 1939 for more details regarding + * the APOP command. + *

+ * @param username The account name being logged in to. + * @param timestamp The timestamp string to combine with the secret. + * @param secret The shared secret which produces the MD5 digest when + * combined with the timestamp. + * @return True if the login attempt was successful, false if not. + * @exception IOException If a network I/O error occurs in the process of + * logging in. + * @exception NoSuchAlgorithmException If the MD5 encryption algorithm + * cannot be instantiated by the Java runtime system. + ***/ + public boolean login(String username, String timestamp, String secret) + throws IOException, NoSuchAlgorithmException + { + int i; + byte[] digest; + StringBuffer buffer, digestBuffer; + MessageDigest md5; + + if (getState() != AUTHORIZATION_STATE) + return false; + + md5 = MessageDigest.getInstance("MD5"); + timestamp += secret; + digest = md5.digest(timestamp.getBytes()); + digestBuffer = new StringBuffer(128); + + for (i = 0; i < digest.length; i++) + digestBuffer.append(Integer.toHexString(digest[i] & 0xff)); + + buffer = new StringBuffer(256); + buffer.append(username); + buffer.append(' '); + buffer.append(digestBuffer.toString()); + + if (sendCommand(POP3Command.APOP, buffer.toString()) != POP3Reply.OK) + return false; + + setState(TRANSACTION_STATE); + + return true; + } + + + /*** + * Logout of the POP3 server. To fully disconnect from the server + * you must call + * {@link org.apache.commons.net.pop3.POP3#disconnect disconnect }. + * A logout attempt is valid in any state. If + * the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * , it enters the + * {@link org.apache.commons.net.pop3.POP3#UPDATE_STATE UPDATE_STATE } + * on a successful logout. + *

+ * @return True if the logout attempt was successful, false if not. + * @exception IOException If a network I/O error occurs in the process + * of logging out. + ***/ + public boolean logout() throws IOException + { + if (getState() == TRANSACTION_STATE) + setState(UPDATE_STATE); + sendCommand(POP3Command.QUIT); + return (_replyCode == POP3Reply.OK); + } + + + /*** + * Send a NOOP command to the POP3 server. This is useful for keeping + * a connection alive since most POP3 servers will timeout after 10 + * minutes of inactivity. A noop attempt will only succeed if + * the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . + *

+ * @return True if the noop attempt was successful, false if not. + * @exception IOException If a network I/O error occurs in the process of + * sending the NOOP command. + ***/ + public boolean noop() throws IOException + { + if (getState() == TRANSACTION_STATE) + return (sendCommand(POP3Command.NOOP) == POP3Reply.OK); + return false; + } + + + /*** + * Delete a message from the POP3 server. The message is only marked + * for deletion by the server. If you decide to unmark the message, you + * must issuse a {@link #reset reset } command. Messages marked + * for deletion are only deleted by the server on + * {@link #logout logout }. + * A delete attempt can only succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . + *

+ * @param messageId The message number to delete. + * @return True if the deletion attempt was successful, false if not. + * @exception IOException If a network I/O error occurs in the process of + * sending the delete command. + ***/ + public boolean deleteMessage(int messageId) throws IOException + { + if (getState() == TRANSACTION_STATE) + return (sendCommand(POP3Command.DELE, Integer.toString(messageId)) + == POP3Reply.OK); + return false; + } + + + /*** + * Reset the POP3 session. This is useful for undoing any message + * deletions that may have been performed. A reset attempt can only + * succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . + *

+ * @return True if the reset attempt was successful, false if not. + * @exception IOException If a network I/O error occurs in the process of + * sending the reset command. + ***/ + public boolean reset() throws IOException + { + if (getState() == TRANSACTION_STATE) + return (sendCommand(POP3Command.RSET) == POP3Reply.OK); + return false; + } + + /*** + * Get the mailbox status. A status attempt can only + * succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns a POP3MessageInfo instance + * containing the number of messages in the mailbox and the total + * size of the messages in bytes. Returns null if the status the + * attempt fails. + *

+ * @return A POP3MessageInfo instance containing the number of + * messages in the mailbox and the total size of the messages + * in bytes. Returns null if the status the attempt fails. + * @exception IOException If a network I/O error occurs in the process of + * sending the status command. + ***/ + public POP3MessageInfo status() throws IOException + { + if (getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.STAT) != POP3Reply.OK) + return null; + return __parseStatus(_lastReplyLine.substring(3)); + } + + + /*** + * List an individual message. A list attempt can only + * succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns a POP3MessageInfo instance + * containing the number of the listed message and the + * size of the message in bytes. Returns null if the list + * attempt fails (e.g., if the specified message number does + * not exist). + *

+ * @param messageId The number of the message list. + * @return A POP3MessageInfo instance containing the number of the + * listed message and the size of the message in bytes. Returns + * null if the list attempt fails. + * @exception IOException If a network I/O error occurs in the process of + * sending the list command. + ***/ + public POP3MessageInfo listMessage(int messageId) throws IOException + { + if (getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.LIST, Integer.toString(messageId)) + != POP3Reply.OK) + return null; + return __parseStatus(_lastReplyLine.substring(3)); + } + + + /*** + * List all messages. A list attempt can only + * succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns an array of POP3MessageInfo instances, + * each containing the number of a message and its size in bytes. + * If there are no messages, this method returns a zero length array. + * If the list attempt fails, it returns null. + *

+ * @return An array of POP3MessageInfo instances representing all messages + * in the order they appear in the mailbox, + * each containing the number of a message and its size in bytes. + * If there are no messages, this method returns a zero length array. + * If the list attempt fails, it returns null. + * @exception IOException If a network I/O error occurs in the process of + * sending the list command. + ***/ + public POP3MessageInfo[] listMessages() throws IOException + { + POP3MessageInfo[] messages; + Enumeration en; + int line; + + if (getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.LIST) != POP3Reply.OK) + return null; + getAdditionalReply(); + + // This could be a zero length array if no messages present + messages = new POP3MessageInfo[_replyLines.size() - 2]; + en = _replyLines.elements(); + + // Skip first line + en.nextElement(); + + // Fetch lines. + for (line = 0; line < messages.length; line++) + messages[line] = __parseStatus(en.nextElement()); + + return messages; + } + + /*** + * List the unique identifier for a message. A list attempt can only + * succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns a POP3MessageInfo instance + * containing the number of the listed message and the + * unique identifier for that message. Returns null if the list + * attempt fails (e.g., if the specified message number does + * not exist). + *

+ * @param messageId The number of the message list. + * @return A POP3MessageInfo instance containing the number of the + * listed message and the unique identifier for that message. + * Returns null if the list attempt fails. + * @exception IOException If a network I/O error occurs in the process of + * sending the list unique identifier command. + ***/ + public POP3MessageInfo listUniqueIdentifier(int messageId) + throws IOException + { + if (getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.UIDL, Integer.toString(messageId)) + != POP3Reply.OK) + return null; + return __parseUID(_lastReplyLine.substring(3)); + } + + + /*** + * List the unique identifiers for all messages. A list attempt can only + * succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns an array of POP3MessageInfo instances, + * each containing the number of a message and its unique identifier. + * If there are no messages, this method returns a zero length array. + * If the list attempt fails, it returns null. + *

+ * @return An array of POP3MessageInfo instances representing all messages + * in the order they appear in the mailbox, + * each containing the number of a message and its unique identifier + * If there are no messages, this method returns a zero length array. + * If the list attempt fails, it returns null. + * @exception IOException If a network I/O error occurs in the process of + * sending the list unique identifier command. + ***/ + public POP3MessageInfo[] listUniqueIdentifiers() throws IOException + { + POP3MessageInfo[] messages; + Enumeration en; + int line; + + if (getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.UIDL) != POP3Reply.OK) + return null; + getAdditionalReply(); + + // This could be a zero length array if no messages present + messages = new POP3MessageInfo[_replyLines.size() - 2]; + en = _replyLines.elements(); + + // Skip first line + en.nextElement(); + + // Fetch lines. + for (line = 0; line < messages.length; line++) + messages[line] = __parseUID(en.nextElement()); + + return messages; + } + + + /*** + * Retrieve a message from the POP3 server. A retrieve message attempt + * can only succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns a DotTerminatedMessageReader instance + * from which the entire message can be read. + * Returns null if the retrieval attempt fails (e.g., if the specified + * message number does not exist). + *

+ * You must not issue any commands to the POP3 server (i.e., call any + * other methods) until you finish reading the message from the + * returned Reader instance. + * The POP3 protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the POP3 connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param messageId The number of the message to fetch. + * @return A DotTerminatedMessageReader instance + * from which the entire message can be read. + * Returns null if the retrieval attempt fails (e.g., if the specified + * message number does not exist). + * @exception IOException If a network I/O error occurs in the process of + * sending the retrieve message command. + ***/ + public Reader retrieveMessage(int messageId) throws IOException + { + if (getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.RETR, Integer.toString(messageId)) + != POP3Reply.OK) + return null; + + return new DotTerminatedMessageReader(_reader); + } + + + /*** + * Retrieve only the specified top number of lines of a message from the + * POP3 server. A retrieve top lines attempt + * can only succeed if the client is in the + * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } + * . Returns a DotTerminatedMessageReader instance + * from which the specified top number of lines of the message can be + * read. + * Returns null if the retrieval attempt fails (e.g., if the specified + * message number does not exist). + *

+ * You must not issue any commands to the POP3 server (i.e., call any + * other methods) until you finish reading the message from the returned + * Reader instance. + * The POP3 protocol uses the same stream for issuing commands as it does + * for returning results. Therefore the returned Reader actually reads + * directly from the POP3 connection. After the end of message has been + * reached, new commands can be executed and their replies read. If + * you do not follow these requirements, your program will not work + * properly. + *

+ * @param messageId The number of the message to fetch. + * @param numLines The top number of lines to fetch. This must be >= 0. + * @return A DotTerminatedMessageReader instance + * from which the specified top number of lines of the message can be + * read. + * Returns null if the retrieval attempt fails (e.g., if the specified + * message number does not exist). + * @exception IOException If a network I/O error occurs in the process of + * sending the top command. + ***/ + public Reader retrieveMessageTop(int messageId, int numLines) + throws IOException + { + if (numLines < 0 || getState() != TRANSACTION_STATE) + return null; + if (sendCommand(POP3Command.TOP, Integer.toString(messageId) + " " + + Integer.toString(numLines)) != POP3Reply.OK) + return null; + + return new DotTerminatedMessageReader(_reader); + } + + +} + diff --git a/org/apache/commons/net/pop3/POP3Command.java b/org/apache/commons/net/pop3/POP3Command.java new file mode 100644 index 0000000..0f583bc --- /dev/null +++ b/org/apache/commons/net/pop3/POP3Command.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.pop3; + +/*** + * POP3Command stores POP3 command code constants. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class POP3Command +{ + /*** Send user name. ***/ + public static final int USER = 0; + /*** Send password. ***/ + public static final int PASS = 1; + /*** Quit session. ***/ + public static final int QUIT = 2; + /*** Get status. ***/ + public static final int STAT = 3; + /*** List message(s). ***/ + public static final int LIST = 4; + /*** Retrieve message(s). ***/ + public static final int RETR = 5; + /*** Delete message(s). ***/ + public static final int DELE = 6; + /*** No operation. Used as a session keepalive. ***/ + public static final int NOOP = 7; + /*** Reset session. ***/ + public static final int RSET = 8; + /*** Authorization. ***/ + public static final int APOP = 9; + /*** Retrieve top number lines from message. ***/ + public static final int TOP = 10; + /*** List unique message identifier(s). ***/ + public static final int UIDL = 11; + + static final String[] _commands = { + "USER", "PASS", "QUIT", "STAT", "LIST", "RETR", "DELE", "NOOP", "RSET", + "APOP", "TOP", "UIDL" + }; + + // Cannot be instantiated. + private POP3Command() + {} + + /*** + * Get the POP3 protocol string command corresponding to a command code. + *

+ * @return The POP3 protocol string command corresponding to a command code. + ***/ + public static final String getCommand(int command) + { + return _commands[command]; + } +} diff --git a/org/apache/commons/net/pop3/POP3MessageInfo.java b/org/apache/commons/net/pop3/POP3MessageInfo.java new file mode 100644 index 0000000..070fd69 --- /dev/null +++ b/org/apache/commons/net/pop3/POP3MessageInfo.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.pop3; + +/*** + * POP3MessageInfo is used to return information about messages stored on + * a POP3 server. Its fields are used to mean slightly different things + * depending on the information being returned. + *

+ * In response to a status command, number + * contains the number of messages in the mailbox, size + * contains the size of the mailbox in bytes, and identifier + * is null. + *

+ * In response to a message listings, number + * contains the message number, size contains the + * size of the message in bytes, and identifier is null. + *

+ * In response to unique identifier listings, number contains + * the message number, size is undefined, and + * identifier contains the message's unique identifier. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class POP3MessageInfo +{ + public int number; + public int size; + public String identifier; + + /*** + * Creates a POP3MessageInfo instance with number and + * size set to 0, and identifier set to + * null. + ***/ + public POP3MessageInfo() + { + number = size = 0; + identifier = null; + } + + /*** + * Creates a POP3MessageInfo instance with number set + * to num , size set to octets , + * and identifier set to null. + ***/ + public POP3MessageInfo(int num, int octets) + { + number = num; + size = octets; + identifier = null; + } + + /*** + * Creates a POP3MessageInfo instance with number set + * to num , size undefined, + * and identifier set to uid. + ***/ + public POP3MessageInfo(int num, String uid) + { + number = num; + size = -1; + identifier = uid; + } +} diff --git a/org/apache/commons/net/pop3/POP3Reply.java b/org/apache/commons/net/pop3/POP3Reply.java new file mode 100644 index 0000000..08e4246 --- /dev/null +++ b/org/apache/commons/net/pop3/POP3Reply.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.pop3; + +/*** + * POP3Reply stores POP3 reply code constants. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class POP3Reply +{ + /*** The reply code indicating success of an operation. ***/ + public static final int OK = 0; + + /*** The reply code indicating failure of an operation. ***/ + public static final int ERROR = 1; + + // Cannot be instantiated. + private POP3Reply() + {} +} diff --git a/org/apache/commons/net/smtp/RelayPath.java b/org/apache/commons/net/smtp/RelayPath.java new file mode 100644 index 0000000..62d1098 --- /dev/null +++ b/org/apache/commons/net/smtp/RelayPath.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +import java.util.Enumeration; +import java.util.Vector; + +/*** + * A class used to represent forward and reverse relay paths. The + * SMTP MAIL command requires a reverse relay path while the SMTP RCPT + * command requires a forward relay path. See RFC 821 for more details. + * In general, you will not have to deal with relay paths. + *

+ *

+ * @author Daniel F. Savarese + * @see SMTPClient + ***/ + +public final class RelayPath +{ + Vector _path; + String _emailAddress; + + /*** + * Create a relay path with the specified email address as the ultimate + * destination. + *

+ * @param emailAddress The destination email address. + ***/ + public RelayPath(String emailAddress) + { + _path = new Vector(); + _emailAddress = emailAddress; + } + + /*** + * Add a mail relay host to the relay path. Hosts are added left to + * right. For example, the following will create the path + * < @bar.com,@foo.com:foobar@foo.com > + *

+     * path = new RelayPath("foobar@foo.com");
+     * path.addRelay("bar.com");
+     * path.addRelay("foo.com");
+     * 
+ *

+ * @param hostname The host to add to the relay path. + ***/ + public void addRelay(String hostname) + { + _path.addElement(hostname); + } + + /*** + * Return the properly formatted string representation of the relay path. + *

+ * @return The properly formatted string representation of the relay path. + ***/ + @Override + public String toString() + { + StringBuffer buffer = new StringBuffer(); + Enumeration hosts; + + buffer.append('<'); + + hosts = _path.elements(); + + if (hosts.hasMoreElements()) + { + buffer.append('@'); + buffer.append(hosts.nextElement()); + + while (hosts.hasMoreElements()) + { + buffer.append(",@"); + buffer.append(hosts.nextElement()); + } + buffer.append(':'); + } + + buffer.append(_emailAddress); + buffer.append('>'); + + return buffer.toString(); + } + +} diff --git a/org/apache/commons/net/smtp/SMTP.java b/org/apache/commons/net/smtp/SMTP.java new file mode 100644 index 0000000..0a628b1 --- /dev/null +++ b/org/apache/commons/net/smtp/SMTP.java @@ -0,0 +1,777 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ProtocolCommandListener; +import org.apache.commons.net.ProtocolCommandSupport; +import org.apache.commons.net.SocketClient; + +/*** + * SMTP provides the basic the functionality necessary to implement your + * own SMTP client. To derive the full benefits of the SMTP class requires + * some knowledge of the FTP protocol defined in RFC 821. However, there + * is no reason why you should have to use the SMTP class. The + * {@link org.apache.commons.net.smtp.SMTPClient} class, + * derived from SMTP, + * implements all the functionality required of an SMTP client. The + * SMTP class is made public to provide access to various SMTP constants + * and to make it easier for adventurous programmers (or those with + * special needs) to interact with the SMTP protocol and implement their + * own clients. A set of methods with names corresponding to the SMTP + * command names are provided to facilitate this interaction. + *

+ * You should keep in mind that the SMTP server may choose to prematurely + * close a connection for various reasons. The SMTP class will detect a + * premature SMTP server connection closing when it receives a + * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } + * response to a command. + * When that occurs, the SMTP class method encountering that reply will throw + * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} + * . + * SMTPConectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} + * , you must disconnect the connection with + * {@link org.apache.commons.net.SocketClient#disconnect disconnect() } + * to properly clean up the system resources used by SMTP. Before + * disconnecting, you may check the + * last reply code and text with + * {@link #getReplyCode getReplyCode }, + * {@link #getReplyString getReplyString }, + * and {@link #getReplyStrings getReplyStrings}. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @see SMTPClient + * @see SMTPConnectionClosedException + * @see org.apache.commons.net.MalformedServerReplyException + ***/ + +public class SMTP extends SocketClient +{ + /*** The default SMTP port (25). ***/ + public static final int DEFAULT_PORT = 25; + + // We have to ensure that the protocol communication is in ASCII + // but we use ISO-8859-1 just in case 8-bit characters cross + // the wire. + private static final String __DEFAULT_ENCODING = "ISO-8859-1"; + + /** The encoding to use (user-settable) */ + private String encoding = __DEFAULT_ENCODING; + + private StringBuffer __commandBuffer; + + BufferedReader _reader; + BufferedWriter _writer; + int _replyCode; + ArrayList _replyLines; + boolean _newReplyString; + String _replyString; + + /*** + * A ProtocolCommandSupport object used to manage the registering of + * ProtocolCommandListeners and te firing of ProtocolCommandEvents. + ***/ + protected ProtocolCommandSupport _commandSupport_; + + /*** + * The default SMTP constructor. Sets the default port to + * DEFAULT_PORT and initializes internal data structures + * for saving SMTP reply information. + ***/ + public SMTP() + { + setDefaultPort(DEFAULT_PORT); + __commandBuffer = new StringBuffer(); + _replyLines = new ArrayList(); + _newReplyString = false; + _replyString = null; + _commandSupport_ = new ProtocolCommandSupport(this); + } + + /** + * Overloaded constructor where the user may specify a default encoding. + * @param encoding + * @since 2.0 + */ + public SMTP(String encoding) { + this(); + this.encoding = encoding; + } + + private int __sendCommand(String command, String args, boolean includeSpace) + throws IOException + { + String message; + + __commandBuffer.setLength(0); + __commandBuffer.append(command); + + if (args != null) + { + if (includeSpace) + __commandBuffer.append(' '); + __commandBuffer.append(args); + } + + __commandBuffer.append(SocketClient.NETASCII_EOL); + + _writer.write(message = __commandBuffer.toString()); + _writer.flush(); + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireCommandSent(command, message); + + __getReply(); + return _replyCode; + } + + private int __sendCommand(int command, String args, boolean includeSpace) + throws IOException + { + return __sendCommand(SMTPCommand._commands[command], args, includeSpace); + } + + private void __getReply() throws IOException + { + int length; + + _newReplyString = true; + _replyLines.clear(); + + String line = _reader.readLine(); + + if (line == null) + throw new SMTPConnectionClosedException( + "Connection closed without indication."); + + // In case we run into an anomaly we don't want fatal index exceptions + // to be thrown. + length = line.length(); + if (length < 3) + throw new MalformedServerReplyException( + "Truncated server reply: " + line); + + try + { + String code = line.substring(0, 3); + _replyCode = Integer.parseInt(code); + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse response code.\nServer Reply: " + line); + } + + _replyLines.add(line); + + // Get extra lines if message continues. + if (length > 3 && line.charAt(3) == '-') + { + do + { + line = _reader.readLine(); + + if (line == null) + throw new SMTPConnectionClosedException( + "Connection closed without indication."); + + _replyLines.add(line); + + // The length() check handles problems that could arise from readLine() + // returning too soon after encountering a naked CR or some other + // anomaly. + } + while (!(line.length() >= 4 && line.charAt(3) != '-' && + Character.isDigit(line.charAt(0)))); + // This is too strong a condition because a non-conforming server + // could screw things up like ftp.funet.fi does for FTP + // line.startsWith(code))); + } + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); + + if (_replyCode == SMTPReply.SERVICE_NOT_AVAILABLE) + throw new SMTPConnectionClosedException( + "SMTP response 421 received. Server closed connection."); + } + + /*** Initiates control connections and gets initial reply. ***/ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + _reader = + new BufferedReader(new InputStreamReader(_input_, + encoding)); + _writer = + new BufferedWriter(new OutputStreamWriter(_output_, + encoding)); + __getReply(); + + } + + + /*** + * Adds a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.addProtocolCommandListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandistener(ProtocolCommandListener listener) + { + _commandSupport_.removeProtocolCommandListener(listener); + } + + + /*** + * Closes the connection to the SMTP server and sets to null + * some internal data so that the memory may be reclaimed by the + * garbage collector. The reply text and code information from the + * last command is voided so that the memory it used may be reclaimed. + *

+ * @exception IOException If an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + _reader = null; + _writer = null; + _replyString = null; + _replyLines.clear(); + _newReplyString = false; + } + + + /*** + * Sends an SMTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The text representation of the SMTP command to send. + * @param args The arguments to the SMTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the SMTP reply code returned by the server + * in response to the command. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command, String args) throws IOException + { + return __sendCommand(command, args, true); + } + + + /*** + * Sends an SMTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The SMTPCommand constant corresponding to the SMTP command + * to send. + * @param args The arguments to the SMTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the SMTP reply code returned by the server + * in response to the command. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command, String args) throws IOException + { + return sendCommand(SMTPCommand._commands[command], args); + } + + + /*** + * Sends an SMTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The text representation of the SMTP command to send. + * @return The integer value of the SMTP reply code returned by the server + * in response to the command. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Sends an SMTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The SMTPCommand constant corresponding to the SMTP command + * to send. + * @return The integer value of the SMTP reply code returned by the server + * in response to the command. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Returns the integer value of the reply code of the last SMTP reply. + * You will usually only use this method after you connect to the + * SMTP server to check that the connection was successful since + * connect is of type void. + *

+ * @return The integer value of the reply code of the last SMTP reply. + ***/ + public int getReplyCode() + { + return _replyCode; + } + + /*** + * Fetches a reply from the SMTP server and returns the integer reply + * code. After calling this method, the actual reply text can be accessed + * from either calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. Only use this + * method if you are implementing your own SMTP client or if you need to + * fetch a secondary response from the SMTP server. + *

+ * @return The integer value of the reply code of the fetched SMTP reply. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while receiving the + * server reply. + ***/ + public int getReply() throws IOException + { + __getReply(); + return _replyCode; + } + + + /*** + * Returns the lines of text from the last SMTP server response as an array + * of strings, one entry per line. The end of line markers of each are + * stripped from each line. + *

+ * @return The lines of text from the last SMTP response as an array. + ***/ + public String[] getReplyStrings() + { + String[] lines; + lines = new String[_replyLines.size()]; + _replyLines.addAll(Arrays.asList(lines)); + return lines; + } + + /*** + * Returns the entire text of the last SMTP server response exactly + * as it was received, including all end of line markers in NETASCII + * format. + *

+ * @return The entire text from the last SMTP response as a String. + ***/ + public String getReplyString() + { + StringBuilder buffer; + + if (!_newReplyString) + return _replyString; + + buffer = new StringBuilder(); + + for (String line : _replyLines) + { + buffer.append(line); + buffer.append(SocketClient.NETASCII_EOL); + } + + _newReplyString = false; + + return (_replyString = buffer.toString()); + } + + + /*** + * A convenience method to send the SMTP HELO command to the server, + * receive the reply, and return the reply code. + *

+ * @param hostname The hostname of the sender. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int helo(String hostname) throws IOException + { + return sendCommand(SMTPCommand.HELO, hostname); + } + + + /*** + * A convenience method to send the SMTP MAIL command to the server, + * receive the reply, and return the reply code. + *

+ * @param reversePath The reverese path. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int mail(String reversePath) throws IOException + { + return __sendCommand(SMTPCommand.MAIL, reversePath, false); + } + + + /*** + * A convenience method to send the SMTP RCPT command to the server, + * receive the reply, and return the reply code. + *

+ * @param forwardPath The forward path. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rcpt(String forwardPath) throws IOException + { + return __sendCommand(SMTPCommand.RCPT, forwardPath, false); + } + + + /*** + * A convenience method to send the SMTP DATA command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int data() throws IOException + { + return sendCommand(SMTPCommand.DATA); + } + + + /*** + * A convenience method to send the SMTP SEND command to the server, + * receive the reply, and return the reply code. + *

+ * @param reversePath The reverese path. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int send(String reversePath) throws IOException + { + return sendCommand(SMTPCommand.SEND, reversePath); + } + + + /*** + * A convenience method to send the SMTP SOML command to the server, + * receive the reply, and return the reply code. + *

+ * @param reversePath The reverese path. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int soml(String reversePath) throws IOException + { + return sendCommand(SMTPCommand.SOML, reversePath); + } + + + /*** + * A convenience method to send the SMTP SAML command to the server, + * receive the reply, and return the reply code. + *

+ * @param reversePath The reverese path. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int saml(String reversePath) throws IOException + { + return sendCommand(SMTPCommand.SAML, reversePath); + } + + + /*** + * A convenience method to send the SMTP RSET command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rset() throws IOException + { + return sendCommand(SMTPCommand.RSET); + } + + + /*** + * A convenience method to send the SMTP VRFY command to the server, + * receive the reply, and return the reply code. + *

+ * @param user The user address to verify. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int vrfy(String user) throws IOException + { + return sendCommand(SMTPCommand.VRFY, user); + } + + + /*** + * A convenience method to send the SMTP VRFY command to the server, + * receive the reply, and return the reply code. + *

+ * @param name The name to expand. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int expn(String name) throws IOException + { + return sendCommand(SMTPCommand.EXPN, name); + } + + /*** + * A convenience method to send the SMTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help() throws IOException + { + return sendCommand(SMTPCommand.HELP); + } + + /*** + * A convenience method to send the SMTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @param command The command name on which to request help. + * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help(String command) throws IOException + { + return sendCommand(SMTPCommand.HELP, command); + } + + /*** + * A convenience method to send the SMTP NOOP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int noop() throws IOException + { + return sendCommand(SMTPCommand.NOOP); + } + + + /*** + * A convenience method to send the SMTP TURN command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int turn() throws IOException + { + return sendCommand(SMTPCommand.TURN); + } + + + /*** + * A convenience method to send the SMTP QUIT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int quit() throws IOException + { + return sendCommand(SMTPCommand.QUIT); + } + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/smtp/SMTPClient.java b/org/apache/commons/net/smtp/SMTPClient.java new file mode 100644 index 0000000..8b9ed45 --- /dev/null +++ b/org/apache/commons/net/smtp/SMTPClient.java @@ -0,0 +1,607 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +import java.io.IOException; +import java.io.Writer; +import java.net.InetAddress; + +import org.apache.commons.net.io.DotTerminatedMessageWriter; + +/*** + * SMTPClient encapsulates all the functionality necessary to send files + * through an SMTP server. This class takes care of all + * low level details of interacting with an SMTP server and provides + * a convenient higher level interface. As with all classes derived + * from {@link org.apache.commons.net.SocketClient}, + * you must first connect to the server with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before doing anything, and finally + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * after you're completely finished interacting with the server. + * Then you need to check the SMTP reply code to see if the connection + * was successful. For example: + *

+ *    try {
+ *      int reply;
+ *      client.connect("mail.foobar.com");
+ *      System.out.print(client.getReplyString());
+ *
+ *      // After connection attempt, you should check the reply code to verify
+ *      // success.
+ *      reply = client.getReplyCode();
+ *
+ *      if(!SMTPReply.isPositiveCompletion(reply)) {
+ *        client.disconnect();
+ *        System.err.println("SMTP server refused connection.");
+ *        System.exit(1);
+ *      }
+ *
+ *      // Do useful stuff here.
+ *      ...
+ *    } catch(IOException e) {
+ *      if(client.isConnected()) {
+ *        try {
+ *          client.disconnect();
+ *        } catch(IOException f) {
+ *          // do nothing
+ *        }
+ *      }
+ *      System.err.println("Could not connect to server.");
+ *      e.printStackTrace();
+ *      System.exit(1);
+ *    }
+ * 
+ *

+ * Immediately after connecting is the only real time you need to check the + * reply code (because connect is of type void). The convention for all the + * SMTP command methods in SMTPClient is such that they either return a + * boolean value or some other value. + * The boolean methods return true on a successful completion reply from + * the SMTP server and false on a reply resulting in an error condition or + * failure. The methods returning a value other than boolean return a value + * containing the higher level data produced by the SMTP command, or null if a + * reply resulted in an error condition or failure. If you want to access + * the exact SMTP reply code causing a success or failure, you must call + * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode } after + * a success or failure. + *

+ * You should keep in mind that the SMTP server may choose to prematurely + * close a connection for various reasons. The SMTPClient class will detect a + * premature SMTP server connection closing when it receives a + * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } + * response to a command. + * When that occurs, the method encountering that reply will throw + * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} + * . + * SMTPConectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} + * , you must disconnect the connection with + * {@link #disconnect disconnect() } to properly clean up the + * system resources used by SMTPClient. Before disconnecting, you may check + * the last reply code and text with + * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode }, + * {@link org.apache.commons.net.smtp.SMTP#getReplyString getReplyString }, + * and + * {@link org.apache.commons.net.smtp.SMTP#getReplyStrings getReplyStrings}. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @see SMTP + * @see SimpleSMTPHeader + * @see RelayPath + * @see SMTPConnectionClosedException + * @see org.apache.commons.net.MalformedServerReplyException + ***/ + +public class SMTPClient extends SMTP +{ + + /** + * Default SMTPClient constructor. Creates a new SMTPClient instance. + */ + public SMTPClient() { } + + /** + * Overloaded constructor that takes an encoding specification + * @param encoding The encoding to use + * @since 2.0 + */ + public SMTPClient(String encoding) { + super(encoding); + } + + + /*** + * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) + * does not complete the entire sequence of SMTP commands to complete a + * transaction. These types of commands require some action by the + * programmer after the reception of a positive intermediate command. + * After the programmer's code completes its actions, it must call this + * method to receive the completion reply from the server and verify the + * success of the entire transaction. + *

+ * For example, + *

+     * writer = client.sendMessage();
+     * if(writer == null) // failure
+     *   return false;
+     * header =
+     *  new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo");
+     * writer.write(header.toString());
+     * writer.write("This is just a test");
+     * writer.close();
+     * if(!client.completePendingCommand()) // failure
+     *   return false;
+     * 
+ *

+ * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean completePendingCommand() throws IOException + { + return SMTPReply.isPositiveCompletion(getReply()); + } + + + /*** + * Login to the SMTP server by sending the HELO command with the + * given hostname as an argument. Before performing any mail commands, + * you must first login. + *

+ * @param hostname The hostname with which to greet the SMTP server. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean login(String hostname) throws IOException + { + return SMTPReply.isPositiveCompletion(helo(hostname)); + } + + + /*** + * Login to the SMTP server by sending the HELO command with the + * client hostname as an argument. Before performing any mail commands, + * you must first login. + *

+ * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean login() throws IOException + { + String name; + InetAddress host; + + host = getLocalAddress(); + name = host.getHostName(); + + if (name == null) + return false; + + return SMTPReply.isPositiveCompletion(helo(name)); + } + + + /*** + * Set the sender of a message using the SMTP MAIL command, specifying + * a reverse relay path. The sender must be set first before any + * recipients may be specified, otherwise the mail server will reject + * your commands. + *

+ * @param path The reverse relay path pointing back to the sender. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setSender(RelayPath path) throws IOException + { + return SMTPReply.isPositiveCompletion(mail(path.toString())); + } + + + /*** + * Set the sender of a message using the SMTP MAIL command, specifying + * the sender's email address. The sender must be set first before any + * recipients may be specified, otherwise the mail server will reject + * your commands. + *

+ * @param address The sender's email address. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setSender(String address) throws IOException + { + return SMTPReply.isPositiveCompletion(mail("<" + address + ">")); + } + + + /*** + * Add a recipient for a message using the SMTP RCPT command, specifying + * a forward relay path. The sender must be set first before any + * recipients may be specified, otherwise the mail server will reject + * your commands. + *

+ * @param path The forward relay path pointing to the recipient. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean addRecipient(RelayPath path) throws IOException + { + return SMTPReply.isPositiveCompletion(rcpt(path.toString())); + } + + + /*** + * Add a recipient for a message using the SMTP RCPT command, the + * recipient's email address. The sender must be set first before any + * recipients may be specified, otherwise the mail server will reject + * your commands. + *

+ * @param address The recipient's email address. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean addRecipient(String address) throws IOException + { + return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">")); + } + + + + /*** + * Send the SMTP DATA command in preparation to send an email message. + * This method returns a DotTerminatedMessageWriter instance to which + * the message can be written. Null is returned if the DATA command + * fails. + *

+ * You must not issue any commands to the SMTP server (i.e., call any + * (other methods) until you finish writing to the returned Writer + * instance and close it. The SMTP protocol uses the same stream for + * issuing commands as it does for returning results. Therefore the + * returned Writer actually writes directly to the SMTP connection. + * After you close the writer, you can execute new commands. If you + * do not follow these requirements your program will not work properly. + *

+ * You can use the provided + * {@link org.apache.commons.net.smtp.SimpleSMTPHeader} + * class to construct a bare minimum header. + * To construct more complicated headers you should + * refer to RFC 822. When the Java Mail API is finalized, you will be + * able to use it to compose fully compliant Internet text messages. + * The DotTerminatedMessageWriter takes care of doubling line-leading + * dots and ending the message with a single dot upon closing, so all + * you have to worry about is writing the header and the message. + *

+ * Upon closing the returned Writer, you need to call + * {@link #completePendingCommand completePendingCommand() } + * to finalize the transaction and verify its success or failure from + * the server reply. + *

+ * @return A DotTerminatedMessageWriter to which the message (including + * header) can be written. Returns null if the command fails. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public Writer sendMessageData() throws IOException + { + if (!SMTPReply.isPositiveIntermediate(data())) + return null; + + return new DotTerminatedMessageWriter(_writer); + } + + + /*** + * A convenience method for sending short messages. This method fetches + * the Writer returned by {@link #sendMessageData sendMessageData() } + * and writes the specified String to it. After writing the message, + * this method calls {@link #completePendingCommand completePendingCommand() } + * to finalize the transaction and returns + * its success or failure. + *

+ * @param message The short email message to send. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean sendShortMessageData(String message) throws IOException + { + Writer writer; + + writer = sendMessageData(); + + if (writer == null) + return false; + + writer.write(message); + writer.close(); + + return completePendingCommand(); + } + + + /*** + * A convenience method for a sending short email without having to + * explicitly set the sender and recipient(s). This method + * sets the sender and recipient using + * {@link #setSender setSender } and + * {@link #addRecipient addRecipient }, and then sends the + * message using {@link #sendShortMessageData sendShortMessageData }. + *

+ * @param sender The email address of the sender. + * @param recipient The email address of the recipient. + * @param message The short email message to send. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean sendSimpleMessage(String sender, String recipient, + String message) + throws IOException + { + if (!setSender(sender)) + return false; + + if (!addRecipient(recipient)) + return false; + + return sendShortMessageData(message); + } + + + + /*** + * A convenience method for a sending short email without having to + * explicitly set the sender and recipient(s). This method + * sets the sender and recipients using + * {@link #setSender setSender } and + * {@link #addRecipient addRecipient }, and then sends the + * message using {@link #sendShortMessageData sendShortMessageData }. + *

+ * @param sender The email address of the sender. + * @param recipients An array of recipient email addresses. + * @param message The short email message to send. + * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean sendSimpleMessage(String sender, String[] recipients, + String message) + throws IOException + { + boolean oneSuccess = false; + int count; + + if (!setSender(sender)) + return false; + + for (count = 0; count < recipients.length; count++) + { + if (addRecipient(recipients[count])) + oneSuccess = true; + } + + if (!oneSuccess) + return false; + + return sendShortMessageData(message); + } + + + /*** + * Logout of the SMTP server by sending the QUIT command. + *

+ * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean logout() throws IOException + { + return SMTPReply.isPositiveCompletion(quit()); + } + + + + /*** + * Aborts the current mail transaction, resetting all server stored + * sender, recipient, and mail data, cleaing all buffers and tables. + *

+ * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean reset() throws IOException + { + return SMTPReply.isPositiveCompletion(rset()); + } + + + /*** + * Verify that a username or email address is valid, i.e., that mail + * can be delivered to that mailbox on the server. + *

+ * @param username The username or email address to validate. + * @return True if the username is valid, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean verify(String username) throws IOException + { + int result; + + result = vrfy(username); + + return (result == SMTPReply.ACTION_OK || + result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD); + } + + + /*** + * Fetches the system help information from the server and returns the + * full string. + *

+ * @return The system help string obtained from the server. null if the + * information could not be obtained. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String listHelp() throws IOException + { + if (SMTPReply.isPositiveCompletion(help())) + return getReplyString(); + return null; + } + + + /*** + * Fetches the help information for a given command from the server and + * returns the full string. + *

+ * @param command The command on which to ask for help. + * @return The command help string obtained from the server. null if the + * information could not be obtained. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String listHelp(String command) throws IOException + { + if (SMTPReply.isPositiveCompletion(help(command))) + return getReplyString(); + return null; + } + + + /*** + * Sends a NOOP command to the SMTP server. This is useful for preventing + * server timeouts. + *

+ * @return True if successfully completed, false if not. + * @exception SMTPConnectionClosedException + * If the SMTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send SMTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean sendNoOp() throws IOException + { + return SMTPReply.isPositiveCompletion(noop()); + } + +} diff --git a/org/apache/commons/net/smtp/SMTPCommand.java b/org/apache/commons/net/smtp/SMTPCommand.java new file mode 100644 index 0000000..04dbf99 --- /dev/null +++ b/org/apache/commons/net/smtp/SMTPCommand.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +/*** + * SMTPCommand stores a set of constants for SMTP command codes. To interpret + * the meaning of the codes, familiarity with RFC 821 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 821. For those who think in terms of the actual SMTP commands, + * a set of constants such as {@link #HELO HELO } are provided + * where the constant name is the same as the SMTP command. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class SMTPCommand +{ + + + public static final int HELO = 0; + public static final int MAIL = 1; + public static final int RCPT = 2; + public static final int DATA = 3; + public static final int SEND = 4; + public static final int SOML = 5; + public static final int SAML = 6; + public static final int RSET = 7; + public static final int VRFY = 8; + public static final int EXPN = 9; + public static final int HELP = 10; + public static final int NOOP = 11; + public static final int TURN = 12; + public static final int QUIT = 13; + + public static final int HELLO = HELO; + public static final int LOGIN = HELO; + public static final int MAIL_FROM = MAIL; + public static final int RECIPIENT = RCPT; + public static final int SEND_MESSAGE_DATA = DATA; + public static final int SEND_FROM = SEND; + public static final int SEND_OR_MAIL_FROM = SOML; + public static final int SEND_AND_MAIL_FROM = SAML; + public static final int RESET = RSET; + public static final int VERIFY = VRFY; + public static final int EXPAND = EXPN; + // public static final int HELP = HELP; + // public static final int NOOP = NOOP; + // public static final int TURN = TURN; + // public static final int QUIT = QUIT; + public static final int LOGOUT = QUIT; + + // Cannot be instantiated + private SMTPCommand() + {} + + static final String[] _commands = { + "HELO", "MAIL FROM:", "RCPT TO:", "DATA", "SEND FROM:", "SOML FROM:", + "SAML FROM:", "RSET", "VRFY", "EXPN", "HELP", "NOOP", "TURN", "QUIT" + }; + + + /*** + * Retrieve the SMTP protocol command string corresponding to a specified + * command code. + *

+ * @param command The command code. + * @return The SMTP protcol command string corresponding to a specified + * command code. + ***/ + public static final String getCommand(int command) + { + return _commands[command]; + } + +} diff --git a/org/apache/commons/net/smtp/SMTPConnectionClosedException.java b/org/apache/commons/net/smtp/SMTPConnectionClosedException.java new file mode 100644 index 0000000..f9a5762 --- /dev/null +++ b/org/apache/commons/net/smtp/SMTPConnectionClosedException.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +import java.io.IOException; + +/*** + * SMTPConnectionClosedException is used to indicate the premature or + * unexpected closing of an SMTP connection resulting from a + * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } + * response (SMTP reply code 421) to a + * failed SMTP command. This exception is derived from IOException and + * therefore may be caught either as an IOException or specifically as an + * SMTPConnectionClosedException. + *

+ *

+ * @author Daniel F. Savarese + * @see SMTP + * @see SMTPClient + ***/ + +public final class SMTPConnectionClosedException extends IOException +{ + + /*** Constructs a SMTPConnectionClosedException with no message ***/ + public SMTPConnectionClosedException() + { + super(); + } + + /*** + * Constructs a SMTPConnectionClosedException with a specified message. + *

+ * @param message The message explaining the reason for the exception. + ***/ + public SMTPConnectionClosedException(String message) + { + super(message); + } + +} diff --git a/org/apache/commons/net/smtp/SMTPReply.java b/org/apache/commons/net/smtp/SMTPReply.java new file mode 100644 index 0000000..45fd7c8 --- /dev/null +++ b/org/apache/commons/net/smtp/SMTPReply.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +/*** + * SMTPReply stores a set of constants for SMTP reply codes. To interpret + * the meaning of the codes, familiarity with RFC 821 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 821. For those who think in terms of the actual reply code values, + * a set of CODE_NUM constants are provided where NUM is the numerical value + * of the code. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class SMTPReply +{ + + public static final int CODE_211 = 211; + public static final int CODE_214 = 214; + public static final int CODE_215 = 215; + public static final int CODE_220 = 220; + public static final int CODE_221 = 221; + public static final int CODE_250 = 250; + public static final int CODE_251 = 251; + public static final int CODE_354 = 354; + public static final int CODE_421 = 421; + public static final int CODE_450 = 450; + public static final int CODE_451 = 451; + public static final int CODE_452 = 452; + public static final int CODE_500 = 500; + public static final int CODE_501 = 501; + public static final int CODE_502 = 502; + public static final int CODE_503 = 503; + public static final int CODE_504 = 504; + public static final int CODE_550 = 550; + public static final int CODE_551 = 551; + public static final int CODE_552 = 552; + public static final int CODE_553 = 553; + public static final int CODE_554 = 554; + + public static final int SYSTEM_STATUS = CODE_211; + public static final int HELP_MESSAGE = CODE_214; + public static final int SERVICE_READY = CODE_220; + public static final int SERVICE_CLOSING_TRANSMISSION_CHANNEL = CODE_221; + public static final int ACTION_OK = CODE_250; + public static final int USER_NOT_LOCAL_WILL_FORWARD = CODE_251; + public static final int START_MAIL_INPUT = CODE_354; + public static final int SERVICE_NOT_AVAILABLE = CODE_421; + public static final int ACTION_NOT_TAKEN = CODE_450; + public static final int ACTION_ABORTED = CODE_451; + public static final int INSUFFICIENT_STORAGE = CODE_452; + public static final int UNRECOGNIZED_COMMAND = CODE_500; + public static final int SYNTAX_ERROR_IN_ARGUMENTS = CODE_501; + public static final int COMMAND_NOT_IMPLEMENTED = CODE_502; + public static final int BAD_COMMAND_SEQUENCE = CODE_503; + public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = CODE_504; + public static final int MAILBOX_UNAVAILABLE = CODE_550; + public static final int USER_NOT_LOCAL = CODE_551; + public static final int STORAGE_ALLOCATION_EXCEEDED = CODE_552; + public static final int MAILBOX_NAME_NOT_ALLOWED = CODE_553; + public static final int TRANSACTION_FAILED = CODE_554; + + // Cannot be instantiated + private SMTPReply() + {} + + /*** + * Determine if a reply code is a positive preliminary response. All + * codes beginning with a 1 are positive preliminary responses. + * Postitive preliminary responses are used to indicate tentative success. + * No further commands can be issued to the SMTP server after a positive + * preliminary response until a follow up response is received from the + * server. + *

+ * Note: No SMTP commands defined in RFC 822 provide this + * type of reply. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive preliminary response, false + * if not. + ***/ + public static boolean isPositivePreliminary(int reply) + { + return (reply >= 100 && reply < 200); + } + + /*** + * Determine if a reply code is a positive completion response. All + * codes beginning with a 2 are positive completion responses. + * The SMTP server will send a positive completion response on the final + * successful completion of a command. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive completion response, false + * if not. + ***/ + public static boolean isPositiveCompletion(int reply) + { + return (reply >= 200 && reply < 300); + } + + /*** + * Determine if a reply code is a positive intermediate response. All + * codes beginning with a 3 are positive intermediate responses. + * The SMTP server will send a positive intermediate response on the + * successful completion of one part of a multi-part sequence of + * commands. For example, after a successful DATA command, a positive + * intermediate response will be sent to indicate that the server is + * ready to receive the message data. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive intermediate response, false + * if not. + ***/ + public static boolean isPositiveIntermediate(int reply) + { + return (reply >= 300 && reply < 400); + } + + /*** + * Determine if a reply code is a negative transient response. All + * codes beginning with a 4 are negative transient responses. + * The SMTP server will send a negative transient response on the + * failure of a command that can be reattempted with success. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative transient response, false + * if not. + ***/ + public static boolean isNegativeTransient(int reply) + { + return (reply >= 400 && reply < 500); + } + + /*** + * Determine if a reply code is a negative permanent response. All + * codes beginning with a 5 are negative permanent responses. + * The SMTP server will send a negative permanent response on the + * failure of a command that cannot be reattempted with success. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative permanent response, false + * if not. + ***/ + public static boolean isNegativePermanent(int reply) + { + return (reply >= 500 && reply < 600); + } + +} diff --git a/org/apache/commons/net/smtp/SimpleSMTPHeader.java b/org/apache/commons/net/smtp/SimpleSMTPHeader.java new file mode 100644 index 0000000..ed0ea4d --- /dev/null +++ b/org/apache/commons/net/smtp/SimpleSMTPHeader.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +/*** + * This class is used to construct a bare minimum + * acceptable header for an email message. To construct more + * complicated headers you should refer to RFC 822. When the + * Java Mail API is finalized, you will be + * able to use it to compose fully compliant Internet text messages. + *

+ * The main purpose of the class is to faciliatate the mail sending + * process, by relieving the programmer from having to explicitly format + * a simple message header. For example: + *

+ * writer = client.sendMessageData();
+ * if(writer == null) // failure
+ *   return false;
+ * header =
+ *    new SimpleSMTPHeader("foobar@foo.com", "foo@bar.com" "Just testing");
+ * header.addCC("bar@foo.com");
+ * header.addHeaderField("Organization", "Foobar, Inc.");
+ * writer.write(header.toString());
+ * writer.write("This is just a test");
+ * writer.close();
+ * if(!client.completePendingCommand()) // failure
+ *   return false;
+ * 
+ *

+ *

+ * @author Daniel F. Savarese + * @see SMTPClient + ***/ + +public class SimpleSMTPHeader +{ + private String __subject, __from, __to; + private StringBuffer __headerFields, __cc; + + /*** + * Creates a new SimpleSMTPHeader instance initialized with the given + * from, to, and subject header field values. + *

+ * @param from The value of the From: header field. This + * should be the sender's email address. + * @param to The value of the To: header field. This + * should be the recipient's email address. + * @param subject The value of the Subject: header field. + * This should be the subject of the message. + ***/ + public SimpleSMTPHeader(String from, String to, String subject) + { + __to = to; + __from = from; + __subject = subject; + __headerFields = new StringBuffer(); + __cc = null; + } + + /*** + * Adds an arbitrary header field with the given value to the article + * header. These headers will be written before the From, To, Subject, and + * Cc fields when the SimpleSMTPHeader is convertered to a string. + * An example use would be: + *

+     * header.addHeaderField("Organization", "Foobar, Inc.");
+     * 
+ *

+ * @param headerField The header field to add, not including the colon. + * @param value The value of the added header field. + ***/ + public void addHeaderField(String headerField, String value) + { + __headerFields.append(headerField); + __headerFields.append(": "); + __headerFields.append(value); + __headerFields.append('\n'); + } + + + /*** + * Add an email address to the CC (carbon copy or courtesy copy) list. + *

+ * @param address The email address to add to the CC list. + ***/ + public void addCC(String address) + { + if (__cc == null) + __cc = new StringBuffer(); + else + __cc.append(", "); + + __cc.append(address); + } + + + /*** + * Converts the SimpleSMTPHeader to a properly formatted header in + * the form of a String, including the blank line used to separate + * the header from the article body. The header fields CC and Subject + * are only included when they are non-null. + *

+ * @return The message header in the form of a String. + ***/ + @Override + public String toString() + { + StringBuffer header = new StringBuffer(); + + if (__headerFields.length() > 0) + header.append(__headerFields.toString()); + + header.append("From: "); + header.append(__from); + header.append("\nTo: "); + header.append(__to); + + if (__cc != null) + { + header.append("\nCc: "); + header.append(__cc.toString()); + } + + if (__subject != null) + { + header.append("\nSubject: "); + header.append(__subject); + } + + header.append('\n'); + header.append('\n'); + + return header.toString(); + } +} + + + diff --git a/org/apache/commons/net/telnet/EchoOptionHandler.java b/org/apache/commons/net/telnet/EchoOptionHandler.java new file mode 100644 index 0000000..8c43f85 --- /dev/null +++ b/org/apache/commons/net/telnet/EchoOptionHandler.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet echo option RFC 857. + *

+ * @author Bruno D'Avanzo + ***/ +public class EchoOptionHandler extends TelnetOptionHandler +{ + /*** + * Constructor for the EchoOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public EchoOptionHandler(boolean initlocal, boolean initremote, + boolean acceptlocal, boolean acceptremote) + { + super(TelnetOption.ECHO, initlocal, initremote, + acceptlocal, acceptremote); + } + + /*** + * Constructor for the EchoOptionHandler. Initial and accept + * behaviour flags are set to false + ***/ + public EchoOptionHandler() + { + super(TelnetOption.ECHO, false, false, false, false); + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], + int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/InvalidTelnetOptionException.java b/org/apache/commons/net/telnet/InvalidTelnetOptionException.java new file mode 100644 index 0000000..740d185 --- /dev/null +++ b/org/apache/commons/net/telnet/InvalidTelnetOptionException.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The InvalidTelnetOptionException is the exception that is + * thrown whenever a TelnetOptionHandler with an invlaid + * option code is registered in TelnetClient with addOptionHandler. + *

+ * @author Bruno D'Avanzo + ***/ +public class InvalidTelnetOptionException extends Exception +{ + + /*** + * Option code + ***/ + private int optionCode = -1; + + /*** + * Error message + ***/ + private String msg; + + /*** + * Constructor for the exception. + *

+ * @param message - Error message. + * @param optcode - Option code. + ***/ + public InvalidTelnetOptionException(String message, int optcode) + { + optionCode = optcode; + msg = message; + } + + /*** + * Gets the error message of ths exception. + *

+ * @return the error message. + ***/ + @Override + public String getMessage() + { + return (msg + ": " + optionCode); + } +} diff --git a/org/apache/commons/net/telnet/SimpleOptionHandler.java b/org/apache/commons/net/telnet/SimpleOptionHandler.java new file mode 100644 index 0000000..3395508 --- /dev/null +++ b/org/apache/commons/net/telnet/SimpleOptionHandler.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Simple option handler that can be used for options + * that don't require subnegotiation. + *

+ * @author Bruno D'Avanzo + ***/ +public class SimpleOptionHandler extends TelnetOptionHandler +{ + /*** + * Constructor for the SimpleOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param optcode - option code. + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public SimpleOptionHandler(int optcode, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote) + { + super(optcode, initlocal, initremote, + acceptlocal, acceptremote); + } + + /*** + * Constructor for the SimpleOptionHandler. Initial and accept + * behaviour flags are set to false + *

+ * @param optcode - option code. + ***/ + public SimpleOptionHandler(int optcode) + { + super(optcode, false, false, false, false); + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/SuppressGAOptionHandler.java b/org/apache/commons/net/telnet/SuppressGAOptionHandler.java new file mode 100644 index 0000000..aa18452 --- /dev/null +++ b/org/apache/commons/net/telnet/SuppressGAOptionHandler.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet suppress go ahead option RFC 858. + *

+ * @author Bruno D'Avanzo + ***/ +public class SuppressGAOptionHandler extends TelnetOptionHandler +{ + /*** + * Constructor for the SuppressGAOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public SuppressGAOptionHandler(boolean initlocal, boolean initremote, + boolean acceptlocal, boolean acceptremote) + { + super(TelnetOption.SUPPRESS_GO_AHEAD, initlocal, initremote, + acceptlocal, acceptremote); + } + + /*** + * Constructor for the SuppressGAOptionHandler. Initial and accept + * behaviour flags are set to false + ***/ + public SuppressGAOptionHandler() + { + super(TelnetOption.SUPPRESS_GO_AHEAD, false, false, false, false); + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/Telnet.java b/org/apache/commons/net/telnet/Telnet.java new file mode 100644 index 0000000..c05b563 --- /dev/null +++ b/org/apache/commons/net/telnet/Telnet.java @@ -0,0 +1,1317 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.OutputStream; +import java.io.IOException; +import org.apache.commons.net.SocketClient; + +/** + * @author Daniel F. Savarese + * @author Bruno D'Avanzo + */ + +class Telnet extends SocketClient +{ + static final boolean debug = /*true;*/ false; + + static final boolean debugoptions = /*true;*/ false; + + static final byte[] _COMMAND_DO = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.DO + }; + + static final byte[] _COMMAND_DONT = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.DONT + }; + + static final byte[] _COMMAND_WILL = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.WILL + }; + + static final byte[] _COMMAND_WONT = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.WONT + }; + + static final byte[] _COMMAND_SB = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.SB + }; + + static final byte[] _COMMAND_SE = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.SE + }; + + static final int _WILL_MASK = 0x01, _DO_MASK = 0x02, + _REQUESTED_WILL_MASK = 0x04, _REQUESTED_DO_MASK = 0x08; + + /* public */ + static final int DEFAULT_PORT = 23; + + int[] _doResponse, _willResponse, _options; + + /* TERMINAL-TYPE option (start)*/ + /*** + * Terminal type option + ***/ + protected static final int TERMINAL_TYPE = 24; + + /*** + * Send (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_SEND = 1; + + /*** + * Is (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_IS = 0; + + /*** + * Is sequence (for subnegotiation) + ***/ + static final byte[] _COMMAND_IS = { + (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS + }; + + /*** + * Terminal type + ***/ + private String terminalType = null; + /* TERMINAL-TYPE option (end)*/ + + /* open TelnetOptionHandler functionality (start)*/ + /*** + * Array of option handlers + ***/ + private TelnetOptionHandler optionHandlers[]; + + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting AYT (start)*/ + /*** + * AYT sequence + ***/ + static final byte[] _COMMAND_AYT = { + (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT + }; + + /*** + * monitor to wait for AYT + ***/ + private Object aytMonitor = new Object(); + + /*** + * flag for AYT + ***/ + private boolean aytFlag = true; + /* Code Section added for supporting AYT (end)*/ + + /*** + * The stream on which to spy + ***/ + private OutputStream spyStream = null; + + /*** + * The notification handler + ***/ + private TelnetNotificationHandler __notifhand = null; + /*** + * Empty Constructor + ***/ + Telnet() + { + setDefaultPort(DEFAULT_PORT); + _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + optionHandlers = + new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; + } + + /* TERMINAL-TYPE option (start)*/ + /*** + * This constructor lets you specify the terminal type. + *

+ * @param termtype - terminal type to be negotiated (ej. VT100) + ***/ + Telnet(String termtype) + { + setDefaultPort(DEFAULT_PORT); + _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + terminalType = termtype; + optionHandlers = + new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; + } + /* TERMINAL-TYPE option (end)*/ + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a will has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsWill(int option) + { + return ((_options[option] & _WILL_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a wont has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsWont(int option) + { + return !_stateIsWill(option); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a do has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsDo(int option) + { + return ((_options[option] & _DO_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a dont has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsDont(int option) + { + return !_stateIsDo(option); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a will has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedWill(int option) + { + return ((_options[option] & _REQUESTED_WILL_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a wont has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedWont(int option) + { + return !_requestedWill(option); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a do has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedDo(int option) + { + return ((_options[option] & _REQUESTED_DO_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a dont has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedDont(int option) + { + return !_requestedDo(option); + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWill(int option) + { + _options[option] |= _WILL_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (_requestedWill(option)) + { + if (optionHandlers[option] != null) + { + optionHandlers[option].setWill(true); + + int subneg[] = + optionHandlers[option].startSubnegotiationLocal(); + + if (subneg != null) + { + try + { + _sendSubnegotiation(subneg); + } + catch (IOException e) + { + System.err.println( + "Exception in option subnegotiation" + + e.getMessage()); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setDo(int option) + { + _options[option] |= _DO_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (_requestedDo(option)) + { + if (optionHandlers[option] != null) + { + optionHandlers[option].setDo(true); + + int subneg[] = + optionHandlers[option].startSubnegotiationRemote(); + + if (subneg != null) + { + try + { + _sendSubnegotiation(subneg); + } + catch (IOException e) + { + System.err.println("Exception in option subnegotiation" + + e.getMessage()); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantWill(int option) + { + _options[option] |= _REQUESTED_WILL_MASK; + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantDo(int option) + { + _options[option] |= _REQUESTED_DO_MASK; + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWont(int option) + { + _options[option] &= ~_WILL_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + optionHandlers[option].setWill(false); + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setDont(int option) + { + _options[option] &= ~_DO_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + optionHandlers[option].setDo(false); + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantWont(int option) + { + _options[option] &= ~_REQUESTED_WILL_MASK; + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantDont(int option) + { + _options[option] &= ~_REQUESTED_DO_MASK; + } + + /** + * Processes a DO request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processDo(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED DO: " + + TelnetOption.getOption(option)); + } + + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_DO, + option); + } + + boolean acceptNewState = false; + + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + acceptNewState = optionHandlers[option].getAcceptLocal(); + } + else + { + /* open TelnetOptionHandler functionality (end)*/ + /* TERMINAL-TYPE option (start)*/ + if (option == TERMINAL_TYPE) + { + if ((terminalType != null) && (terminalType.length() > 0)) + { + acceptNewState = true; + } + } + /* TERMINAL-TYPE option (end)*/ + /* open TelnetOptionHandler functionality (start)*/ + } + /* open TelnetOptionHandler functionality (end)*/ + + if (_willResponse[option] > 0) + { + --_willResponse[option]; + if (_willResponse[option] > 0 && _stateIsWill(option)) + { + --_willResponse[option]; + } + } + + if (_willResponse[option] == 0) + { + if (_requestedWont(option)) + { + + switch (option) + { + + default: + break; + + } + + + if (acceptNewState) + { + _setWantWill(option); + _sendWill(option); + } + else + { + ++_willResponse[option]; + _sendWont(option); + } + } + else + { + // Other end has acknowledged option. + + switch (option) + { + + default: + break; + + } + + } + } + + _setWill(option); + } + + /** + * Processes a DONT request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processDont(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED DONT: " + + TelnetOption.getOption(option)); + } + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_DONT, + option); + } + if (_willResponse[option] > 0) + { + --_willResponse[option]; + if (_willResponse[option] > 0 && _stateIsWont(option)) + { + --_willResponse[option]; + } + } + + if (_willResponse[option] == 0 && _requestedWill(option)) + { + + switch (option) + { + + default: + break; + + } + + /* FIX for a BUG in the negotiation (start)*/ + if ((_stateIsWill(option)) || (_requestedWill(option))) + { + _sendWont(option); + } + + _setWantWont(option); + /* FIX for a BUG in the negotiation (end)*/ + } + + _setWont(option); + } + + + /** + * Processes a WILL request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processWill(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED WILL: " + + TelnetOption.getOption(option)); + } + + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_WILL, + option); + } + + boolean acceptNewState = false; + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + acceptNewState = optionHandlers[option].getAcceptRemote(); + } + /* open TelnetOptionHandler functionality (end)*/ + + if (_doResponse[option] > 0) + { + --_doResponse[option]; + if (_doResponse[option] > 0 && _stateIsDo(option)) + { + --_doResponse[option]; + } + } + + if (_doResponse[option] == 0 && _requestedDont(option)) + { + + switch (option) + { + + default: + break; + + } + + + if (acceptNewState) + { + _setWantDo(option); + _sendDo(option); + } + else + { + ++_doResponse[option]; + _sendDont(option); + } + } + + _setDo(option); + } + + /** + * Processes a WONT request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processWont(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED WONT: " + + TelnetOption.getOption(option)); + } + + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_WONT, + option); + } + + if (_doResponse[option] > 0) + { + --_doResponse[option]; + if (_doResponse[option] > 0 && _stateIsDont(option)) + { + --_doResponse[option]; + } + } + + if (_doResponse[option] == 0 && _requestedDo(option)) + { + + switch (option) + { + + default: + break; + + } + + /* FIX for a BUG in the negotiation (start)*/ + if ((_stateIsDo(option)) || (_requestedDo(option))) + { + _sendDont(option); + } + + _setWantDont(option); + /* FIX for a BUG in the negotiation (end)*/ + } + + _setDont(option); + } + + /* TERMINAL-TYPE option (start)*/ + /** + * Processes a suboption negotiation. + * + * @param suboption - subnegotiation data received + * @param suboptionLength - length of data received + * @throws IOException - Exception in I/O. + **/ + void _processSuboption(int suboption[], int suboptionLength) + throws IOException + { + if (debug) + { + System.err.println("PROCESS SUBOPTION."); + } + + /* open TelnetOptionHandler functionality (start)*/ + if (suboptionLength > 0) + { + if (optionHandlers[suboption[0]] != null) + { + int responseSuboption[] = + optionHandlers[suboption[0]].answerSubnegotiation(suboption, + suboptionLength); + _sendSubnegotiation(responseSuboption); + } + else + { + if (suboptionLength > 1) + { + if (debug) + { + for (int ii = 0; ii < suboptionLength; ii++) + { + System.err.println("SUB[" + ii + "]: " + + suboption[ii]); + } + } + if ((suboption[0] == TERMINAL_TYPE) + && (suboption[1] == TERMINAL_TYPE_SEND)) + { + _sendTerminalType(); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sends terminal type information. + *

+ * @throws IOException - Exception in I/O. + ***/ + final synchronized void _sendTerminalType() + throws IOException + { + if (debug) + { + System.err.println("SEND TERMINAL-TYPE: " + terminalType); + } + if (terminalType != null) + { + _output_.write(_COMMAND_SB); + _output_.write(_COMMAND_IS); + _output_.write(terminalType.getBytes()); + _output_.write(_COMMAND_SE); + _output_.flush(); + } + } + + /* TERMINAL-TYPE option (end)*/ + + /* open TelnetOptionHandler functionality (start)*/ + /** + * Manages subnegotiation for Terminal Type. + * + * @param subn - subnegotiation data to be sent + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendSubnegotiation(int subn[]) + throws IOException + { + if (debug) + { + System.err.println("SEND SUBNEGOTIATION: "); + if (subn != null) + { + for (int ii = 0; ii < subn.length; ii++) + { + System.err.println("subn[" + ii + "]=" + subn[ii]); + } + } + } + if (subn != null) + { + byte byteresp[] = new byte[subn.length]; + for (int ii = 0; ii < subn.length; ii++) + { + byteresp[ii] = (byte) subn[ii]; + } + + _output_.write(_COMMAND_SB); + _output_.write(byteresp); + _output_.write(_COMMAND_SE); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + } + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting AYT (start)*/ + /*** + * Processes the response of an AYT + ***/ + final synchronized void _processAYTResponse() + { + if (!aytFlag) + { + synchronized (aytMonitor) + { + aytFlag = true; + try + { + aytMonitor.notifyAll(); + } + catch (IllegalMonitorStateException e) + { + System.err.println("Exception notifying:" + e.getMessage()); + } + } + } + } + /* Code Section added for supporting AYT (end)*/ + + /*** + * Called upon connection. + *

+ * @throws IOException - Exception in I/O. + ***/ + @Override + protected void _connectAction_() throws IOException + { + /* (start). BUGFIX: clean the option info for each connection*/ + for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) + { + _doResponse[ii] = 0; + _willResponse[ii] = 0; + _options[ii] = 0; + if (optionHandlers[ii] != null) + { + optionHandlers[ii].setDo(false); + optionHandlers[ii].setWill(false); + } + } + /* (end). BUGFIX: clean the option info for each connection*/ + + super._connectAction_(); + _input_ = new BufferedInputStream(_input_); + _output_ = new BufferedOutputStream(_output_); + + /* open TelnetOptionHandler functionality (start)*/ + for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) + { + if (optionHandlers[ii] != null) + { + if (optionHandlers[ii].getInitLocal()) + { + try + { + _requestWill(optionHandlers[ii].getOptionCode()); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + + if (optionHandlers[ii].getInitRemote()) + { + try + { + _requestDo(optionHandlers[ii].getOptionCode()); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /** + * Sends a DO. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendDo(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("DO: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_DO); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a DO. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestDo(int option) + throws IOException + { + if ((_doResponse[option] == 0 && _stateIsDo(option)) + || _requestedDo(option)) + { + return ; + } + _setWantDo(option); + ++_doResponse[option]; + _sendDo(option); + } + + /** + * Sends a DONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendDont(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("DONT: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_DONT); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a DONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestDont(int option) + throws IOException + { + if ((_doResponse[option] == 0 && _stateIsDont(option)) + || _requestedDont(option)) + { + return ; + } + _setWantDont(option); + ++_doResponse[option]; + _sendDont(option); + } + + + /** + * Sends a WILL. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendWill(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("WILL: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_WILL); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a WILL. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestWill(int option) + throws IOException + { + if ((_willResponse[option] == 0 && _stateIsWill(option)) + || _requestedWill(option)) + { + return ; + } + _setWantWill(option); + ++_doResponse[option]; + _sendWill(option); + } + + /** + * Sends a WONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendWont(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("WONT: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_WONT); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a WONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestWont(int option) + throws IOException + { + if ((_willResponse[option] == 0 && _stateIsWont(option)) + || _requestedWont(option)) + { + return ; + } + _setWantWont(option); + ++_doResponse[option]; + _sendWont(option); + } + + /** + * Sends a byte. + * + * @param b - byte to send + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendByte(int b) + throws IOException + { + _output_.write(b); + + /* Code Section added for supporting spystreams (start)*/ + _spyWrite(b); + /* Code Section added for supporting spystreams (end)*/ + + } + + /* Code Section added for supporting AYT (start)*/ + /** + * Sends an Are You There sequence and waits for the result. + * + * @param timeout - Time to wait for a response (millis.) + * @throws IOException - Exception in I/O. + * @throws IllegalArgumentException - Illegal argument + * @throws InterruptedException - Interrupted during wait. + * @return true if AYT received a response, false otherwise + **/ + final boolean _sendAYT(long timeout) + throws IOException, IllegalArgumentException, InterruptedException + { + boolean retValue = false; + synchronized (aytMonitor) + { + synchronized (this) + { + aytFlag = false; + _output_.write(_COMMAND_AYT); + _output_.flush(); + } + + try + { + aytMonitor.wait(timeout); + if (aytFlag == false) + { + retValue = false; + aytFlag = true; + } + else + { + retValue = true; + } + } + catch (IllegalMonitorStateException e) + { + System.err.println("Exception processing AYT:" + + e.getMessage()); + } + } + + return (retValue); + } + /* Code Section added for supporting AYT (end)*/ + + /* open TelnetOptionHandler functionality (start)*/ + + /** + * Registers a new TelnetOptionHandler for this telnet to use. + * + * @param opthand - option handler to be registered. + * @throws InvalidTelnetOptionException - The option code is invalid. + **/ + void addOptionHandler(TelnetOptionHandler opthand) + throws InvalidTelnetOptionException + { + int optcode = opthand.getOptionCode(); + if (TelnetOption.isValidOption(optcode)) + { + if (optionHandlers[optcode] == null) + { + optionHandlers[optcode] = opthand; + if (isConnected()) + { + if (opthand.getInitLocal()) + { + try + { + _requestWill(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + + if (opthand.getInitRemote()) + { + try + { + _requestDo(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + } + } + else + { + throw (new InvalidTelnetOptionException( + "Already registered option", optcode)); + } + } + else + { + throw (new InvalidTelnetOptionException( + "Invalid Option Code", optcode)); + } + } + + /** + * Unregisters a TelnetOptionHandler. + * + * @param optcode - Code of the option to be unregistered. + * @throws InvalidTelnetOptionException - The option code is invalid. + **/ + void deleteOptionHandler(int optcode) + throws InvalidTelnetOptionException + { + if (TelnetOption.isValidOption(optcode)) + { + if (optionHandlers[optcode] == null) + { + throw (new InvalidTelnetOptionException( + "Unregistered option", optcode)); + } + else + { + TelnetOptionHandler opthand = optionHandlers[optcode]; + optionHandlers[optcode] = null; + + if (opthand.getWill()) + { + try + { + _requestWont(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while turning off option: " + + e.getMessage()); + } + } + + if (opthand.getDo()) + { + try + { + _requestDont(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while turning off option: " + + e.getMessage()); + } + } + } + } + else + { + throw (new InvalidTelnetOptionException( + "Invalid Option Code", optcode)); + } + } + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting spystreams (start)*/ + /*** + * Registers an OutputStream for spying what's going on in + * the Telnet session. + *

+ * @param spystream - OutputStream on which session activity + * will be echoed. + ***/ + void _registerSpyStream(OutputStream spystream) + { + spyStream = spystream; + } + + /*** + * Stops spying this Telnet. + *

+ ***/ + void _stopSpyStream() + { + spyStream = null; + } + + /*** + * Sends a read char on the spy stream. + *

+ * @param ch - character read from the session + ***/ + void _spyRead(int ch) + { + if (spyStream != null) + { + try + { + if (ch != '\r') + { + spyStream.write(ch); + if (ch == '\n') + { + spyStream.write('\r'); + } + spyStream.flush(); + } + } + catch (IOException e) + { + spyStream = null; + } + } + } + + /*** + * Sends a written char on the spy stream. + *

+ * @param ch - character written to the session + ***/ + void _spyWrite(int ch) + { + if (!(_stateIsDo(TelnetOption.ECHO) + && _requestedDo(TelnetOption.ECHO))) + { + if (spyStream != null) + { + try + { + spyStream.write(ch); + spyStream.flush(); + } + catch (IOException e) + { + spyStream = null; + } + } + } + } + /* Code Section added for supporting spystreams (end)*/ + + /*** + * Registers a notification handler to which will be sent + * notifications of received telnet option negotiation commands. + *

+ * @param notifhand - TelnetNotificationHandler to be registered + ***/ + public void registerNotifHandler(TelnetNotificationHandler notifhand) + { + __notifhand = notifhand; + } + + /*** + * Unregisters the current notification handler. + *

+ ***/ + public void unregisterNotifHandler() + { + __notifhand = null; + } +} diff --git a/org/apache/commons/net/telnet/TelnetClient.java b/org/apache/commons/net/telnet/TelnetClient.java new file mode 100644 index 0000000..3237779 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetClient.java @@ -0,0 +1,306 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.commons.net.io.FromNetASCIIInputStream; +import org.apache.commons.net.io.ToNetASCIIOutputStream; + +/*** + * The TelnetClient class implements the simple network virtual + * terminal (NVT) for the Telnet protocol according to RFC 854. It + * does not implement any of the extra Telnet options because it + * is meant to be used within a Java program providing automated + * access to Telnet accessible resources. + *

+ * The class can be used by first connecting to a server using the + * SocketClient + * {@link org.apache.commons.net.SocketClient#connect connect} + * method. Then an InputStream and OutputStream for sending and + * receiving data over the Telnet connection can be obtained by + * using the {@link #getInputStream getInputStream() } and + * {@link #getOutputStream getOutputStream() } methods. + * When you finish using the streams, you must call + * {@link #disconnect disconnect } rather than simply + * closing the streams. + *

+ *

+ * @author Daniel F. Savarese + * @author Bruno D'Avanzo + ***/ + +public class TelnetClient extends Telnet +{ + private InputStream __input; + private OutputStream __output; + protected boolean readerThread = true; + + /*** + * Default TelnetClient constructor. + ***/ + public TelnetClient() + { + /* TERMINAL-TYPE option (start)*/ + super ("VT100"); + /* TERMINAL-TYPE option (end)*/ + __input = null; + __output = null; + } + + /* TERMINAL-TYPE option (start)*/ + public TelnetClient(String termtype) + { + super (termtype); + __input = null; + __output = null; + } + /* TERMINAL-TYPE option (end)*/ + + void _flushOutputStream() throws IOException + { + _output_.flush(); + } + void _closeOutputStream() throws IOException + { + _output_.close(); + } + + /*** + * Handles special connection requirements. + *

+ * @exception IOException If an error occurs during connection setup. + ***/ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + InputStream input; + TelnetInputStream tmp; + + if (FromNetASCIIInputStream.isConversionRequired()) + input = new FromNetASCIIInputStream(_input_); + else + input = _input_; + + + tmp = new TelnetInputStream(input, this, readerThread); + if(readerThread) + { + tmp._start(); + } + // __input CANNOT refer to the TelnetInputStream. We run into + // blocking problems when some classes use TelnetInputStream, so + // we wrap it with a BufferedInputStream which we know is safe. + // This blocking behavior requires further investigation, but right + // now it looks like classes like InputStreamReader are not implemented + // in a safe manner. + __input = new BufferedInputStream(tmp); + __output = new ToNetASCIIOutputStream(new TelnetOutputStream(this)); + } + + /*** + * Disconnects the telnet session, closing the input and output streams + * as well as the socket. If you have references to the + * input and output streams of the telnet connection, you should not + * close them yourself, but rather call disconnect to properly close + * the connection. + ***/ + @Override + public void disconnect() throws IOException + { + if (__input != null) + __input.close(); + if (__output != null) + __output.close(); + super.disconnect(); + } + + /*** + * Returns the telnet connection output stream. You should not close the + * stream when you finish with it. Rather, you should call + * {@link #disconnect disconnect }. + *

+ * @return The telnet connection output stream. + ***/ + public OutputStream getOutputStream() + { + return __output; + } + + /*** + * Returns the telnet connection input stream. You should not close the + * stream when you finish with it. Rather, you should call + * {@link #disconnect disconnect }. + *

+ * @return The telnet connection input stream. + ***/ + public InputStream getInputStream() + { + return __input; + } + + /*** + * Returns the state of the option on the local side. + *

+ * @param option - Option to be checked. + *

+ * @return The state of the option on the local side. + ***/ + public boolean getLocalOptionState(int option) + { + /* BUG (option active when not already acknowledged) (start)*/ + return (_stateIsWill(option) && _requestedWill(option)); + /* BUG (option active when not already acknowledged) (end)*/ + } + + /*** + * Returns the state of the option on the remote side. + *

+ * @param option - Option to be checked. + *

+ * @return The state of the option on the remote side. + ***/ + public boolean getRemoteOptionState(int option) + { + /* BUG (option active when not already acknowledged) (start)*/ + return (_stateIsDo(option) && _requestedDo(option)); + /* BUG (option active when not already acknowledged) (end)*/ + } + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting AYT (start)*/ + + /*** + * Sends an Are You There sequence and waits for the result. + *

+ * @throws InterruptedException + * @throws IllegalArgumentException + * @throws IOException + *

+ * @param timeout - Time to wait for a response (millis.) + *

+ * @return true if AYT received a response, false otherwise + ***/ + public boolean sendAYT(long timeout) + throws IOException, IllegalArgumentException, InterruptedException + { + return (_sendAYT(timeout)); + } + /* Code Section added for supporting AYT (start)*/ + + /* open TelnetOptionHandler functionality (start)*/ + + /*** + * Registers a new TelnetOptionHandler for this telnet client to use. + *

+ * @param opthand - option handler to be registered. + *

+ * @throws InvalidTelnetOptionException + ***/ + @Override + public void addOptionHandler(TelnetOptionHandler opthand) + throws InvalidTelnetOptionException + { + super.addOptionHandler(opthand); + } + /* open TelnetOptionHandler functionality (end)*/ + + /*** + * Unregisters a TelnetOptionHandler. + *

+ * @param optcode - Code of the option to be unregistered. + *

+ * @throws InvalidTelnetOptionException + ***/ + @Override + public void deleteOptionHandler(int optcode) + throws InvalidTelnetOptionException + { + super.deleteOptionHandler(optcode); + } + + /* Code Section added for supporting spystreams (start)*/ + /*** + * Registers an OutputStream for spying what's going on in + * the TelnetClient session. + *

+ * @param spystream - OutputStream on which session activity + * will be echoed. + ***/ + public void registerSpyStream(OutputStream spystream) + { + super._registerSpyStream(spystream); + } + + /*** + * Stops spying this TelnetClient. + *

+ ***/ + public void stopSpyStream() + { + super._stopSpyStream(); + } + /* Code Section added for supporting spystreams (end)*/ + + /*** + * Registers a notification handler to which will be sent + * notifications of received telnet option negotiation commands. + *

+ * @param notifhand - TelnetNotificationHandler to be registered + ***/ + @Override + public void registerNotifHandler(TelnetNotificationHandler notifhand) + { + super.registerNotifHandler(notifhand); + } + + /*** + * Unregisters the current notification handler. + *

+ ***/ + @Override + public void unregisterNotifHandler() + { + super.unregisterNotifHandler(); + } + + /*** + * Sets the status of the reader thread. + * The reader thread status will apply to all subsequent connections + *

+ * @param flag - true switches the reader thread on, false switches it off + ***/ + public void setReaderThread(boolean flag) + { + readerThread = flag; + } + + /*** + * Gets the status of the reader thread. + *

+ * @return true if the reader thread is on, false otherwise + ***/ + public boolean getReaderThread() + { + return (readerThread); + } +} diff --git a/org/apache/commons/net/telnet/TelnetCommand.java b/org/apache/commons/net/telnet/TelnetCommand.java new file mode 100644 index 0000000..725057b --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetCommand.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/** + * The TelnetCommand class cannot be instantiated and only serves as a + * storehouse for telnet command constants. + * @author Daniel F. Savarese + * @see org.apache.commons.net.telnet.Telnet + * @see org.apache.commons.net.telnet.TelnetClient + */ + +public final class TelnetCommand +{ + /*** The maximum value a command code can have. This value is 255. ***/ + public static final int MAX_COMMAND_VALUE = 255; + + /*** Interpret As Command code. Value is 255 according to RFC 854. ***/ + public static final int IAC = 255; + + /*** Don't use option code. Value is 254 according to RFC 854. ***/ + public static final int DONT = 254; + + /*** Request to use option code. Value is 253 according to RFC 854. ***/ + public static final int DO = 253; + + /*** Refuse to use option code. Value is 252 according to RFC 854. ***/ + public static final int WONT = 252; + + /*** Agree to use option code. Value is 251 according to RFC 854. ***/ + public static final int WILL = 251; + + /*** Start subnegotiation code. Value is 250 according to RFC 854. ***/ + public static final int SB = 250; + + /*** Go Ahead code. Value is 249 according to RFC 854. ***/ + public static final int GA = 249; + + /*** Erase Line code. Value is 248 according to RFC 854. ***/ + public static final int EL = 248; + + /*** Erase Character code. Value is 247 according to RFC 854. ***/ + public static final int EC = 247; + + /*** Are You There code. Value is 246 according to RFC 854. ***/ + public static final int AYT = 246; + + /*** Abort Output code. Value is 245 according to RFC 854. ***/ + public static final int AO = 245; + + /*** Interrupt Process code. Value is 244 according to RFC 854. ***/ + public static final int IP = 244; + + /*** Break code. Value is 243 according to RFC 854. ***/ + public static final int BREAK = 243; + + /*** Data mark code. Value is 242 according to RFC 854. ***/ + public static final int DM = 242; + + /*** No Operation code. Value is 241 according to RFC 854. ***/ + public static final int NOP = 241; + + /*** End subnegotiation code. Value is 240 according to RFC 854. ***/ + public static final int SE = 240; + + /*** End of record code. Value is 239. ***/ + public static final int EOR = 239; + + /*** Abort code. Value is 238. ***/ + public static final int ABORT = 238; + + /*** Suspend process code. Value is 237. ***/ + public static final int SUSP = 237; + + /*** End of file code. Value is 236. ***/ + public static final int EOF = 236; + + /*** Synchronize code. Value is 242. ***/ + public static final int SYNCH = 242; + + /*** String representations of commands. ***/ + private static final String __commandString[] = { + "IAC", "DONT", "DO", "WONT", "WILL", "SB", "GA", "EL", "EC", "AYT", + "AO", "IP", "BRK", "DMARK", "NOP", "SE", "EOR", "ABORT", "SUSP", "EOF" + }; + + private static final int __FIRST_COMMAND = IAC; + private static final int __LAST_COMMAND = EOF; + + /*** + * Returns the string representation of the telnet protocol command + * corresponding to the given command code. + *

+ * @param code The command code of the telnet protocol command. + * @return The string representation of the telnet protocol command. + ***/ + public static final String getCommand(int code) + { + return __commandString[__FIRST_COMMAND - code]; + } + + /*** + * Determines if a given command code is valid. Returns true if valid, + * false if not. + *

+ * @param code The command code to test. + * @return True if the command code is valid, false if not. + **/ + public static final boolean isValidCommand(int code) + { + return (code <= __FIRST_COMMAND && code >= __LAST_COMMAND); + } + + // Cannot be instantiated + private TelnetCommand() + { } +} diff --git a/org/apache/commons/net/telnet/TelnetInputStream.java b/org/apache/commons/net/telnet/TelnetInputStream.java new file mode 100644 index 0000000..8a83b68 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetInputStream.java @@ -0,0 +1,630 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; + +/*** + * + *

+ * + *

+ *

+ * @author Daniel F. Savarese + * @author Bruno D'Avanzo + ***/ + + +final class TelnetInputStream extends BufferedInputStream implements Runnable +{ + static final int _STATE_DATA = 0, _STATE_IAC = 1, _STATE_WILL = 2, + _STATE_WONT = 3, _STATE_DO = 4, _STATE_DONT = 5, + _STATE_SB = 6, _STATE_SE = 7, _STATE_CR = 8, _STATE_IAC_SB = 9; + + private boolean __hasReachedEOF, __isClosed; + private boolean __readIsWaiting; + private int __receiveState, __queueHead, __queueTail, __bytesAvailable; + private int[] __queue; + private TelnetClient __client; + private Thread __thread; + private IOException __ioException; + + /* TERMINAL-TYPE option (start)*/ + private int __suboption[] = new int[256]; + private int __suboption_count = 0; + /* TERMINAL-TYPE option (end)*/ + + private boolean __threaded; + + TelnetInputStream(InputStream input, TelnetClient client, + boolean readerThread) + { + super(input); + __client = client; + __receiveState = _STATE_DATA; + __isClosed = true; + __hasReachedEOF = false; + // Make it 2049, because when full, one slot will go unused, and we + // want a 2048 byte buffer just to have a round number (base 2 that is) + __queue = new int[2049]; + __queueHead = 0; + __queueTail = 0; + __bytesAvailable = 0; + __ioException = null; + __readIsWaiting = false; + __threaded = false; + if(readerThread) + __thread = new Thread(this); + else + __thread = null; + } + + TelnetInputStream(InputStream input, TelnetClient client) { + this(input, client, true); + } + + void _start() + { + if(__thread == null) + return; + + int priority; + __isClosed = false; + // TODO remove this + // Need to set a higher priority in case JVM does not use pre-emptive + // threads. This should prevent scheduler induced deadlock (rather than + // deadlock caused by a bug in this code). + priority = Thread.currentThread().getPriority() + 1; + if (priority > Thread.MAX_PRIORITY) + priority = Thread.MAX_PRIORITY; + __thread.setPriority(priority); + __thread.setDaemon(true); + __thread.start(); + __threaded = true; + } + + + // synchronized(__client) critical sections are to protect against + // TelnetOutputStream writing through the telnet client at same time + // as a processDo/Will/etc. command invoked from TelnetInputStream + // tries to write. + private int __read(boolean mayBlock) throws IOException + { + int ch; + +_loop: + while (true) + { + + // If there is no more data AND we were told not to block, just return -2. (More efficient than exception.) + if(!mayBlock && super.available() == 0) + return -2; + + // Otherwise, exit only when we reach end of stream. + if ((ch = super.read()) < 0) + return -1; + + ch = (ch & 0xff); + + /* Code Section added for supporting AYT (start)*/ + synchronized (__client) + { + __client._processAYTResponse(); + } + /* Code Section added for supporting AYT (end)*/ + + /* Code Section added for supporting spystreams (start)*/ + __client._spyRead(ch); + /* Code Section added for supporting spystreams (end)*/ + +_mainSwitch: + switch (__receiveState) + { + + case _STATE_CR: + if (ch == '\0') + { + // Strip null + continue; + } + // How do we handle newline after cr? + // else if (ch == '\n' && _requestedDont(TelnetOption.ECHO) && + + // Handle as normal data by falling through to _STATE_DATA case + + case _STATE_DATA: + if (ch == TelnetCommand.IAC) + { + __receiveState = _STATE_IAC; + continue; + } + + + if (ch == '\r') + { + synchronized (__client) + { + if (__client._requestedDont(TelnetOption.BINARY)) + __receiveState = _STATE_CR; + else + __receiveState = _STATE_DATA; + } + } + else + __receiveState = _STATE_DATA; + break; + + case _STATE_IAC: + switch (ch) + { + case TelnetCommand.WILL: + __receiveState = _STATE_WILL; + continue; + case TelnetCommand.WONT: + __receiveState = _STATE_WONT; + continue; + case TelnetCommand.DO: + __receiveState = _STATE_DO; + continue; + case TelnetCommand.DONT: + __receiveState = _STATE_DONT; + continue; + /* TERMINAL-TYPE option (start)*/ + case TelnetCommand.SB: + __suboption_count = 0; + __receiveState = _STATE_SB; + continue; + /* TERMINAL-TYPE option (end)*/ + case TelnetCommand.IAC: + __receiveState = _STATE_DATA; + break; + default: + break; + } + __receiveState = _STATE_DATA; + continue; + case _STATE_WILL: + synchronized (__client) + { + __client._processWill(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + case _STATE_WONT: + synchronized (__client) + { + __client._processWont(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + case _STATE_DO: + synchronized (__client) + { + __client._processDo(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + case _STATE_DONT: + synchronized (__client) + { + __client._processDont(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + /* TERMINAL-TYPE option (start)*/ + case _STATE_SB: + switch (ch) + { + case TelnetCommand.IAC: + __receiveState = _STATE_IAC_SB; + continue; + default: + // store suboption char + __suboption[__suboption_count++] = ch; + break; + } + __receiveState = _STATE_SB; + continue; + case _STATE_IAC_SB: + switch (ch) + { + case TelnetCommand.SE: + synchronized (__client) + { + __client._processSuboption(__suboption, __suboption_count); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + default: + __receiveState = _STATE_SB; + break; + } + __receiveState = _STATE_DATA; + continue; + /* TERMINAL-TYPE option (end)*/ + } + + break; + } + + return ch; + } + + // synchronized(__client) critical sections are to protect against + // TelnetOutputStream writing through the telnet client at same time + // as a processDo/Will/etc. command invoked from TelnetInputStream + // tries to write. + private void __processChar(int ch) throws InterruptedException + { + // Critical section because we're altering __bytesAvailable, + // __queueTail, and the contents of _queue. + synchronized (__queue) + { + while (__bytesAvailable >= __queue.length - 1) + { + // The queue is full. We need to wait before adding any more data to it. Hopefully the stream owner + // will consume some data soon! + if(__threaded) + { + __queue.notify(); + try + { + __queue.wait(); + } + catch (InterruptedException e) + { + throw e; + } + } + else + { + // We've been asked to add another character to the queue, but it is already full and there's + // no other thread to drain it. This should not have happened! + throw new IllegalStateException("Queue is full! Cannot process another character."); + } + } + + // Need to do this in case we're not full, but block on a read + if (__readIsWaiting && __threaded) + { + __queue.notify(); + } + + __queue[__queueTail] = ch; + ++__bytesAvailable; + + if (++__queueTail >= __queue.length) + __queueTail = 0; + } + } + + @Override + public int read() throws IOException + { + // Critical section because we're altering __bytesAvailable, + // __queueHead, and the contents of _queue in addition to + // testing value of __hasReachedEOF. + synchronized (__queue) + { + + while (true) + { + if (__ioException != null) + { + IOException e; + e = __ioException; + __ioException = null; + throw e; + } + + if (__bytesAvailable == 0) + { + // Return -1 if at end of file + if (__hasReachedEOF) + return -1; + + // Otherwise, we have to wait for queue to get something + if(__threaded) + { + __queue.notify(); + try + { + __readIsWaiting = true; + __queue.wait(); + __readIsWaiting = false; + } + catch (InterruptedException e) + { + throw new InterruptedIOException("Fatal thread interruption during read."); + } + } + else + { + //__alreadyread = false; + __readIsWaiting = true; + int ch; + boolean mayBlock = true; // block on the first read only + + do + { + try + { + if ((ch = __read(mayBlock)) < 0) + if(ch != -2) + return (ch); + } + catch (InterruptedIOException e) + { + synchronized (__queue) + { + __ioException = e; + __queue.notifyAll(); + try + { + __queue.wait(100); + } + catch (InterruptedException interrupted) + { + } + } + return (-1); + } + + + try + { + if(ch != -2) + { + __processChar(ch); + } + } + catch (InterruptedException e) + { + if (__isClosed) + return (-1); + } + + // Reads should not block on subsequent iterations. Potentially, this could happen if the + // remaining buffered socket data consists entirely of Telnet command sequence and no "user" data. + mayBlock = false; + + } + // Continue reading as long as there is data available and the queue is not full. + while (super.available() > 0 && __bytesAvailable < __queue.length - 1); + + __readIsWaiting = false; + } + continue; + } + else + { + int ch; + + ch = __queue[__queueHead]; + + if (++__queueHead >= __queue.length) + __queueHead = 0; + + --__bytesAvailable; + + // Need to explicitly notify() so available() works properly + if(__bytesAvailable == 0 && __threaded) { + __queue.notify(); + } + + return ch; + } + } + } + } + + + /*** + * Reads the next number of bytes from the stream into an array and + * returns the number of bytes read. Returns -1 if the end of the + * stream has been reached. + *

+ * @param buffer The byte array in which to store the data. + * @return The number of bytes read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[]) throws IOException + { + return read(buffer, 0, buffer.length); + } + + + /*** + * Reads the next number of bytes from the stream into an array and returns + * the number of bytes read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + *

+ * @param buffer The byte array in which to store the data. + * @param offset The offset into the array at which to start storing data. + * @param length The number of bytes to read. + * @return The number of bytes read. Returns -1 if the + * end of the stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[], int offset, int length) throws IOException + { + int ch, off; + + if (length < 1) + return 0; + + // Critical section because run() may change __bytesAvailable + synchronized (__queue) + { + if (length > __bytesAvailable) + length = __bytesAvailable; + } + + if ((ch = read()) == -1) + return -1; + + off = offset; + + do + { + buffer[offset++] = (byte)ch; + } + while (--length > 0 && (ch = read()) != -1); + + //__client._spyRead(buffer, off, offset - off); + return (offset - off); + } + + + /*** Returns false. Mark is not supported. ***/ + @Override + public boolean markSupported() + { + return false; + } + + @Override + public int available() throws IOException + { + // Critical section because run() may change __bytesAvailable + synchronized (__queue) + { + return __bytesAvailable; + } + } + + + // Cannot be synchronized. Will cause deadlock if run() is blocked + // in read because BufferedInputStream read() is synchronized. + @Override + public void close() throws IOException + { + // Completely disregard the fact thread may still be running. + // We can't afford to block on this close by waiting for + // thread to terminate because few if any JVM's will actually + // interrupt a system read() from the interrupt() method. + super.close(); + + synchronized (__queue) + { + __hasReachedEOF = true; + __isClosed = true; + + if (__thread != null && __thread.isAlive()) + { + __thread.interrupt(); + } + + __queue.notifyAll(); + } + + __threaded = false; + } + + public void run() + { + int ch; + + try + { +_outerLoop: + while (!__isClosed) + { + try + { + if ((ch = __read(true)) < 0) + break; + } + catch (InterruptedIOException e) + { + synchronized (__queue) + { + __ioException = e; + __queue.notifyAll(); + try + { + __queue.wait(100); + } + catch (InterruptedException interrupted) + { + if (__isClosed) + break _outerLoop; + } + continue; + } + } catch(RuntimeException re) { + // We treat any runtime exceptions as though the + // stream has been closed. We close the + // underlying stream just to be sure. + super.close(); + // Breaking the loop has the effect of setting + // the state to closed at the end of the method. + break _outerLoop; + } + + try + { + __processChar(ch); + } + catch (InterruptedException e) + { + if (__isClosed) + break _outerLoop; + } + } + } + catch (IOException ioe) + { + synchronized (__queue) + { + __ioException = ioe; + } + } + + synchronized (__queue) + { + __isClosed = true; // Possibly redundant + __hasReachedEOF = true; + __queue.notify(); + } + + __threaded = false; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/telnet/TelnetNotificationHandler.java b/org/apache/commons/net/telnet/TelnetNotificationHandler.java new file mode 100644 index 0000000..d509021 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetNotificationHandler.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The TelnetNotificationHandler interface can be used to handle + * notification of options negotiation commands received on a telnet + * session. + *

+ * The user can implement this interface and register a + * TelnetNotificationHandler by using the registerNotificationHandler() + * of TelnetClient to be notified of option negotiation commands. + *

+ *

+ * @author Bruno D'Avanzo + ***/ + +public interface TelnetNotificationHandler +{ + /*** + * The remote party sent a DO command. + ***/ + public static final int RECEIVED_DO = 1; + + /*** + * The remote party sent a DONT command. + ***/ + public static final int RECEIVED_DONT = 2; + + /*** + * The remote party sent a WILL command. + ***/ + public static final int RECEIVED_WILL = 3; + + /*** + * The remote party sent a WONT command. + ***/ + public static final int RECEIVED_WONT = 4; + + /*** + * Callback method called when TelnetClient receives an option + * negotiation command. + *

+ * @param negotiation_code - type of negotiation command received + * (RECEIVED_DO, RECEIVED_DONT, RECEIVED_WILL, RECEIVED_WONT) + *

+ * @param option_code - code of the option negotiated + *

+ ***/ + public void receivedNegotiation(int negotiation_code, int option_code); +} diff --git a/org/apache/commons/net/telnet/TelnetOption.java b/org/apache/commons/net/telnet/TelnetOption.java new file mode 100644 index 0000000..77799b6 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetOption.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The TelnetOption class cannot be instantiated and only serves as a + * storehouse for telnet option constants. + *

+ * Details regarding Telnet option specification can be found in RFC 855. + *

+ *

+ * @author Daniel F. Savarese + * @see org.apache.commons.net.telnet.Telnet + * @see org.apache.commons.net.telnet.TelnetClient + ***/ + +public class TelnetOption +{ + /*** The maximum value an option code can have. This value is 255. ***/ + public static final int MAX_OPTION_VALUE = 255; + + public static final int BINARY = 0; + + public static final int ECHO = 1; + + public static final int PREPARE_TO_RECONNECT = 2; + + public static final int SUPPRESS_GO_AHEAD = 3; + + public static final int APPROXIMATE_MESSAGE_SIZE = 4; + + public static final int STATUS = 5; + + public static final int TIMING_MARK = 6; + + public static final int REMOTE_CONTROLLED_TRANSMISSION = 7; + + public static final int NEGOTIATE_OUTPUT_LINE_WIDTH = 8; + + public static final int NEGOTIATE_OUTPUT_PAGE_SIZE = 9; + + public static final int NEGOTIATE_CARRIAGE_RETURN = 10; + + public static final int NEGOTIATE_HORIZONTAL_TAB_STOP = 11; + + public static final int NEGOTIATE_HORIZONTAL_TAB = 12; + + public static final int NEGOTIATE_FORMFEED = 13; + + public static final int NEGOTIATE_VERTICAL_TAB_STOP = 14; + + public static final int NEGOTIATE_VERTICAL_TAB = 15; + + public static final int NEGOTIATE_LINEFEED = 16; + + public static final int EXTENDED_ASCII = 17; + + public static final int FORCE_LOGOUT = 18; + + public static final int BYTE_MACRO = 19; + + public static final int DATA_ENTRY_TERMINAL = 20; + + public static final int SUPDUP = 21; + + public static final int SUPDUP_OUTPUT = 22; + + public static final int SEND_LOCATION = 23; + + public static final int TERMINAL_TYPE = 24; + + public static final int END_OF_RECORD = 25; + + public static final int TACACS_USER_IDENTIFICATION = 26; + + public static final int OUTPUT_MARKING = 27; + + public static final int TERMINAL_LOCATION_NUMBER = 28; + + public static final int REGIME_3270 = 29; + + public static final int X3_PAD = 30; + + public static final int WINDOW_SIZE = 31; + + public static final int TERMINAL_SPEED = 32; + + public static final int REMOTE_FLOW_CONTROL = 33; + + public static final int LINEMODE = 34; + + public static final int X_DISPLAY_LOCATION = 35; + + public static final int OLD_ENVIRONMENT_VARIABLES = 36; + + public static final int AUTHENTICATION = 37; + + public static final int ENCRYPTION = 38; + + public static final int NEW_ENVIRONMENT_VARIABLES = 39; + + public static final int EXTENDED_OPTIONS_LIST = 255; + + private static final int __FIRST_OPTION = BINARY; + private static final int __LAST_OPTION = EXTENDED_OPTIONS_LIST; + + private static final String __optionString[] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS", + "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", + "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", + "BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", "TACACS UID", + "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", + "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", "TN3270E", "XAUTH", "CHARSET", "RSP", + "Com Port Control", "Suppress Local Echo", "Start TLS", + "KERMIT", "SEND-URL", "FORWARD_X", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "TELOPT PRAGMA LOGON", "TELOPT SSPI LOGON", + "TELOPT PRAGMA HEARTBEAT", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "Extended-Options-List" + }; + + + /*** + * Returns the string representation of the telnet protocol option + * corresponding to the given option code. + *

+ * @param code The option code of the telnet protocol option + * @return The string representation of the telnet protocol option. + ***/ + public static final String getOption(int code) + { + if(__optionString[code].length() == 0) + { + return "UNASSIGNED"; + } + else + { + return __optionString[code]; + } + } + + + /*** + * Determines if a given option code is valid. Returns true if valid, + * false if not. + *

+ * @param code The option code to test. + * @return True if the option code is valid, false if not. + **/ + public static final boolean isValidOption(int code) + { + return (code <= __LAST_OPTION); + } + + // Cannot be instantiated + private TelnetOption() + { } +} diff --git a/org/apache/commons/net/telnet/TelnetOptionHandler.java b/org/apache/commons/net/telnet/TelnetOptionHandler.java new file mode 100644 index 0000000..52486ba --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetOptionHandler.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The TelnetOptionHandler class is the base class to be used + * for implementing handlers for telnet options. + *

+ * TelnetOptionHandler implements basic option handling + * functionality and defines abstract methods that must be + * implemented to define subnegotiation behaviour. + *

+ * @author Bruno D'Avanzo + ***/ +public abstract class TelnetOptionHandler +{ + /*** + * Option code + ***/ + private int optionCode = -1; + + /*** + * true if the option should be activated on the local side + ***/ + private boolean initialLocal = false; + + /*** + * true if the option should be activated on the remote side + ***/ + private boolean initialRemote = false; + + /*** + * true if the option should be accepted on the local side + ***/ + private boolean acceptLocal = false; + + /*** + * true if the option should be accepted on the remote side + ***/ + private boolean acceptRemote = false; + + /*** + * true if the option is active on the local side + ***/ + private boolean doFlag = false; + + /*** + * true if the option is active on the remote side + ***/ + private boolean willFlag = false; + + /*** + * Constructor for the TelnetOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param optcode - Option code. + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public TelnetOptionHandler(int optcode, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote) + { + optionCode = optcode; + initialLocal = initlocal; + initialRemote = initremote; + acceptLocal = acceptlocal; + acceptRemote = acceptremote; + } + + + /*** + * Returns the option code for this option. + *

+ * @return Option code. + ***/ + public int getOptionCode() + { + return (optionCode); + } + + /*** + * Returns a boolean indicating whether to accept a DO + * request coming from the other end. + *

+ * @return true if a DO request shall be accepted. + ***/ + public boolean getAcceptLocal() + { + return (acceptLocal); + } + + /*** + * Returns a boolean indicating whether to accept a WILL + * request coming from the other end. + *

+ * @return true if a WILL request shall be accepted. + ***/ + public boolean getAcceptRemote() + { + return (acceptRemote); + } + + /*** + * Set behaviour of the option for DO requests coming from + * the other end. + *

+ * @param accept - if true, subsequent DO requests will be accepted. + ***/ + public void setAcceptLocal(boolean accept) + { + acceptLocal = accept; + } + + /*** + * Set behaviour of the option for WILL requests coming from + * the other end. + *

+ * @param accept - if true, subsequent WILL requests will be accepted. + ***/ + public void setAcceptRemote(boolean accept) + { + acceptRemote = accept; + } + + /*** + * Returns a boolean indicating whether to send a WILL request + * to the other end upon connection. + *

+ * @return true if a WILL request shall be sent upon connection. + ***/ + public boolean getInitLocal() + { + return (initialLocal); + } + + /*** + * Returns a boolean indicating whether to send a DO request + * to the other end upon connection. + *

+ * @return true if a DO request shall be sent upon connection. + ***/ + public boolean getInitRemote() + { + return (initialRemote); + } + + /*** + * Tells this option whether to send a WILL request upon connection. + *

+ * @param init - if true, a WILL request will be sent upon subsequent + * connections. + ***/ + public void setInitLocal(boolean init) + { + initialLocal = init; + } + + /*** + * Tells this option whether to send a DO request upon connection. + *

+ * @param init - if true, a DO request will be sent upon subsequent + * connections. + ***/ + public void setInitRemote(boolean init) + { + initialRemote = init; + } + + /*** + * Method called upon reception of a subnegotiation for this option + * coming from the other end. + * Must be implemented by the actual TelnetOptionHandler to specify + * which response must be sent for the subnegotiation request. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return response to be sent to the subnegotiation sequence. TelnetClient + * will add IAC SB & IAC SE. null means no response + ***/ + public abstract int[] answerSubnegotiation(int suboptionData[], + int suboptionLength); + + /*** + * This method is invoked whenever this option is acknowledged active on + * the local end (TelnetClient sent a WILL, remote side sent a DO). + * The method is used to specify a subnegotiation sequence that will be + * sent by TelnetClient when the option is activated. + *

+ * @return subnegotiation sequence to be sent by TelnetClient. TelnetClient + * will add IAC SB & IAC SE. null means no subnegotiation. + ***/ + public abstract int[] startSubnegotiationLocal(); + + /*** + * This method is invoked whenever this option is acknowledged active on + * the remote end (TelnetClient sent a DO, remote side sent a WILL). + * The method is used to specify a subnegotiation sequence that will be + * sent by TelnetClient when the option is activated. + *

+ * @return subnegotiation sequence to be sent by TelnetClient. TelnetClient + * will add IAC SB & IAC SE. null means no subnegotiation. + ***/ + public abstract int[] startSubnegotiationRemote(); + + /*** + * Returns a boolean indicating whether a WILL request sent to the other + * side has been acknowledged. + *

+ * @return true if a WILL sent to the other side has been acknowledged. + ***/ + boolean getWill() + { + return willFlag; + } + + /*** + * Tells this option whether a WILL request sent to the other + * side has been acknowledged (invoked by TelnetClient). + *

+ * @param state - if true, a WILL request has been acknowledged. + ***/ + void setWill(boolean state) + { + willFlag = state; + } + + /*** + * Returns a boolean indicating whether a DO request sent to the other + * side has been acknowledged. + *

+ * @return true if a DO sent to the other side has been acknowledged. + ***/ + boolean getDo() + { + return doFlag; + } + + + /*** + * Tells this option whether a DO request sent to the other + * side has been acknowledged (invoked by TelnetClient). + *

+ * @param state - if true, a DO request has been acknowledged. + ***/ + void setDo(boolean state) + { + doFlag = state; + } +} diff --git a/org/apache/commons/net/telnet/TelnetOutputStream.java b/org/apache/commons/net/telnet/TelnetOutputStream.java new file mode 100644 index 0000000..fd796d1 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetOutputStream.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.IOException; +import java.io.OutputStream; + +/*** + * + *

+ * + *

+ *

+ * @author Daniel F. Savarese + ***/ + + +final class TelnetOutputStream extends OutputStream +{ + private TelnetClient __client; + private boolean __convertCRtoCRLF = true; + private boolean __lastWasCR = false; + + TelnetOutputStream(TelnetClient client) + { + __client = client; + } + + + /*** + * Writes a byte to the stream. + *

+ * @param ch The byte to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(int ch) throws IOException + { + + synchronized (__client) + { + ch &= 0xff; + + if (__client._requestedWont(TelnetOption.BINARY)) + { + if (__lastWasCR) + { + if (__convertCRtoCRLF) + { + __client._sendByte('\n'); + if (ch == '\n') + { + __lastWasCR = false; + return ; + } + } + else if (ch != '\n') + __client._sendByte('\0'); + } + + __lastWasCR = false; + + switch (ch) + { + case '\r': + __client._sendByte('\r'); + __lastWasCR = true; + break; + case TelnetCommand.IAC: + __client._sendByte(TelnetCommand.IAC); + __client._sendByte(TelnetCommand.IAC); + break; + default: + __client._sendByte(ch); + break; + } + } + else if (ch == TelnetCommand.IAC) + { + __client._sendByte(ch); + __client._sendByte(TelnetCommand.IAC); + } + else + __client._sendByte(ch); + } + } + + + /*** + * Writes a byte array to the stream. + *

+ * @param buffer The byte array to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(byte buffer[]) throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(byte buffer[], int offset, int length) throws IOException + { + synchronized (__client) + { + while (length-- > 0) + write(buffer[offset++]); + } + } + + /*** Flushes the stream. ***/ + @Override + public void flush() throws IOException + { + __client._flushOutputStream(); + } + + /*** Closes the stream. ***/ + @Override + public void close() throws IOException + { + __client._closeOutputStream(); + } +} diff --git a/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java b/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java new file mode 100644 index 0000000..0cbe0c0 --- /dev/null +++ b/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet terminal type option RFC 1091. + *

+ * @author Bruno D'Avanzo + ***/ +public class TerminalTypeOptionHandler extends TelnetOptionHandler +{ + /*** + * Terminal type + ***/ + private String termType = null; + + /*** + * Terminal type option + ***/ + protected static final int TERMINAL_TYPE = 24; + + /*** + * Send (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_SEND = 1; + + /*** + * Is (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_IS = 0; + + /*** + * Constructor for the TerminalTypeOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param termtype - terminal type that will be negotiated. + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public TerminalTypeOptionHandler(String termtype, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote) + { + super(TelnetOption.TERMINAL_TYPE, initlocal, initremote, + acceptlocal, acceptremote); + termType = termtype; + } + + /*** + * Constructor for the TerminalTypeOptionHandler. Initial and accept + * behaviour flags are set to false + *

+ * @param termtype - terminal type that will be negotiated. + ***/ + public TerminalTypeOptionHandler(String termtype) + { + super(TelnetOption.TERMINAL_TYPE, false, false, false, false); + termType = termtype; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return terminal type information + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + if ((suboptionData != null) && (suboptionLength > 1) + && (termType != null)) + { + if ((suboptionData[0] == TERMINAL_TYPE) + && (suboptionData[1] == TERMINAL_TYPE_SEND)) + { + int response[] = new int[termType.length() + 2]; + + response[0] = TERMINAL_TYPE; + response[1] = TERMINAL_TYPE_IS; + + for (int ii = 0; ii < termType.length(); ii++) + { + response[ii + 2] = termType.charAt(ii); + } + + return response; + } + } + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/WindowSizeOptionHandler.java b/org/apache/commons/net/telnet/WindowSizeOptionHandler.java new file mode 100644 index 0000000..34bb46f --- /dev/null +++ b/org/apache/commons/net/telnet/WindowSizeOptionHandler.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet window size option RFC 1073. + *

+ * @author Yuval Kashtan + * @version $Id: WindowSizeOptionHandler.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 2.0 + ***/ +public class WindowSizeOptionHandler extends TelnetOptionHandler +{ + /*** + * Horizontal Size + ***/ + private int m_nWidth = 80; + + /*** + * Vertical Size + ***/ + private int m_nHeight = 24; + + /*** + * Window size option + ***/ + protected static final int WINDOW_SIZE = 31; + + /*** + * Constructor for the WindowSizeOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param nWidth - Window width. + * @param nHeight - Window Height + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public WindowSizeOptionHandler( + int nWidth, + int nHeight, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote + ) { + super ( + TelnetOption.WINDOW_SIZE, + initlocal, + initremote, + acceptlocal, + acceptremote + ); + + m_nWidth = nWidth; + m_nHeight = nHeight; + } + + /*** + * Constructor for the WindowSizeOptionHandler. Initial and accept + * behaviour flags are set to false + *

+ * @param nWidth - Window width. + * @param nHeight - Window Height + ***/ + public WindowSizeOptionHandler( + int nWidth, + int nHeight + ) { + super ( + TelnetOption.WINDOW_SIZE, + false, + false, + false, + false + ); + + m_nWidth = nWidth; + m_nHeight = nHeight; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return terminal type information + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + * This will send the client Height and Width to the server. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + int nCompoundWindowSize = m_nWidth * 0x10000 + m_nHeight; + int nResponseSize = 5; + int nIndex; + int nShift; + int nTurnedOnBits; + + if ((m_nWidth % 0x100) == 0xFF) { + nResponseSize += 1; + } + + if ((m_nWidth / 0x100) == 0xFF) { + nResponseSize += 1; + } + + if ((m_nHeight % 0x100) == 0xFF) { + nResponseSize += 1; + } + + if ((m_nHeight / 0x100) == 0xFF) { + nResponseSize += 1; + } + + // + // allocate response array + // + int response[] = new int[nResponseSize]; + + // + // Build response array. + // --------------------- + // 1. put option name. + // 2. loop through Window size and fill the values, + // 3. duplicate 'ff' if needed. + // + + response[0] = WINDOW_SIZE; // 1 // + + for ( // 2 // + nIndex=1, nShift = 24; + nIndex < nResponseSize; + nIndex++, nShift -=8 + ) { + nTurnedOnBits = 0xFF; + nTurnedOnBits <<= nShift; + response[nIndex] = (nCompoundWindowSize & nTurnedOnBits) >>> nShift; + + if (response[nIndex] == 0xff) { // 3 // + nIndex++; + response[nIndex] = 0xff; + } + } + + return response; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/tftp/TFTP.java b/org/apache/commons/net/tftp/TFTP.java new file mode 100644 index 0000000..662da11 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTP.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.DatagramPacket; +import java.net.SocketException; + +import org.apache.commons.net.DatagramSocketClient; + +/*** + * The TFTP class exposes a set of methods to allow you to deal with the TFTP + * protocol directly, in case you want to write your own TFTP client or + * server. However, almost every user should only be concerend with + * the {@link org.apache.commons.net.DatagramSocketClient#open open() }, + * and {@link org.apache.commons.net.DatagramSocketClient#close close() }, + * methods. Additionally,the a + * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() } + * method may be of importance for performance tuning. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. + *

+ *

+ * @author Daniel F. Savarese + * @see org.apache.commons.net.DatagramSocketClient + * @see TFTPPacket + * @see TFTPPacketException + * @see TFTPClient + ***/ + +public class TFTP extends DatagramSocketClient +{ + /*** + * The ascii transfer mode. Its value is 0 and equivalent to NETASCII_MODE + ***/ + public static final int ASCII_MODE = 0; + + /*** + * The netascii transfer mode. Its value is 0. + ***/ + public static final int NETASCII_MODE = 0; + + /*** + * The binary transfer mode. Its value is 1 and equivalent to OCTET_MODE. + ***/ + public static final int BINARY_MODE = 1; + + /*** + * The image transfer mode. Its value is 1 and equivalent to OCTET_MODE. + ***/ + public static final int IMAGE_MODE = 1; + + /*** + * The octet transfer mode. Its value is 1. + ***/ + public static final int OCTET_MODE = 1; + + /*** + * The default number of milliseconds to wait to receive a datagram + * before timing out. The default is 5000 milliseconds (5 seconds). + ***/ + public static final int DEFAULT_TIMEOUT = 5000; + + /*** + * The default TFTP port according to RFC 783 is 69. + ***/ + public static final int DEFAULT_PORT = 69; + + /*** + * The size to use for TFTP packet buffers. Its 4 plus the + * TFTPPacket.SEGMENT_SIZE, i.e. 516. + ***/ + static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4; + + /*** A buffer used to accelerate receives in bufferedReceive() ***/ + private byte[] __receiveBuffer; + + /*** A datagram used to minimize memory allocation in bufferedReceive() ***/ + private DatagramPacket __receiveDatagram; + + /*** A datagram used to minimize memory allocation in bufferedSend() ***/ + private DatagramPacket __sendDatagram; + + /*** + * A buffer used to accelerate sends in bufferedSend(). + * It is left package visible so that TFTPClient may be slightly more + * efficient during file sends. It saves the creation of an + * additional buffer and prevents a buffer copy in _newDataPcket(). + ***/ + byte[] _sendBuffer; + + + /*** + * Returns the TFTP string representation of a TFTP transfer mode. + * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer + * mode is specified. + *

+ * @param mode The TFTP transfer mode. One of the MODE constants. + * @return The TFTP string representation of the TFTP transfer mode. + ***/ + public static final String getModeName(int mode) + { + return TFTPRequestPacket._modeStrings[mode]; + } + + /*** + * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT, + * a null socket, and buffered operations disabled. + ***/ + public TFTP() + { + setDefaultTimeout(DEFAULT_TIMEOUT); + __receiveBuffer = null; + __receiveDatagram = null; + } + + /*** + * This method synchronizes a connection by discarding all packets that + * may be in the local socket buffer. This method need only be called + * when you implement your own TFTP client or server. + *

+ * @exception IOException if an I/O error occurs. + ***/ + public final void discardPackets() throws IOException + { + int to; + DatagramPacket datagram; + + datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE); + + to = getSoTimeout(); + setSoTimeout(1); + + try + { + while (true) + _socket_.receive(datagram); + } + catch (SocketException e) + { + // Do nothing. We timed out so we hope we're caught up. + } + catch (InterruptedIOException e) + { + // Do nothing. We timed out so we hope we're caught up. + } + + setSoTimeout(to); + } + + + /*** + * This is a special method to perform a more efficient packet receive. + * It should only be used after calling + * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps() + * initializes a set of buffers used internally that prevent the new + * allocation of a DatagramPacket and byte array for each send and receive. + * To use these buffers you must call the bufferedReceive() and + * bufferedSend() methods instead of send() and receive(). You must + * also be certain that you don't manipulate the resulting packet in + * such a way that it interferes with future buffered operations. + * For example, a TFTPDataPacket received with bufferedReceive() will + * have a reference to the internal byte buffer. You must finish using + * this data before calling bufferedReceive() again, or else the data + * will be overwritten by the the call. + *

+ * @return The TFTPPacket received. + * @exception InterruptedIOException If a socket timeout occurs. The + * Java documentation claims an InterruptedIOException is thrown + * on a DatagramSocket timeout, but in practice we find a + * SocketException is thrown. You should catch both to be safe. + * @exception SocketException If a socket timeout occurs. The + * Java documentation claims an InterruptedIOException is thrown + * on a DatagramSocket timeout, but in practice we find a + * SocketException is thrown. You should catch both to be safe. + * @exception IOException If some other I/O error occurs. + * @exception TFTPPacketException If an invalid TFTP packet is received. + ***/ + public final TFTPPacket bufferedReceive() throws IOException, + InterruptedIOException, SocketException, TFTPPacketException + { + __receiveDatagram.setData(__receiveBuffer); + __receiveDatagram.setLength(__receiveBuffer.length); + _socket_.receive(__receiveDatagram); + + return TFTPPacket.newTFTPPacket(__receiveDatagram); + } + + /*** + * This is a special method to perform a more efficient packet send. + * It should only be used after calling + * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps() + * initializes a set of buffers used internally that prevent the new + * allocation of a DatagramPacket and byte array for each send and receive. + * To use these buffers you must call the bufferedReceive() and + * bufferedSend() methods instead of send() and receive(). You must + * also be certain that you don't manipulate the resulting packet in + * such a way that it interferes with future buffered operations. + * For example, a TFTPDataPacket received with bufferedReceive() will + * have a reference to the internal byte buffer. You must finish using + * this data before calling bufferedReceive() again, or else the data + * will be overwritten by the the call. + *

+ * @param packet The TFTP packet to send. + * @exception IOException If some I/O error occurs. + ***/ + public final void bufferedSend(TFTPPacket packet) throws IOException + { + _socket_.send(packet._newDatagram(__sendDatagram, _sendBuffer)); + } + + + /*** + * Initializes the internal buffers. Buffers are used by + * {@link #bufferedSend bufferedSend() } and + * {@link #bufferedReceive bufferedReceive() }. This + * method must be called before calling either one of those two + * methods. When you finish using buffered operations, you must + * call {@link #endBufferedOps endBufferedOps() }. + ***/ + public final void beginBufferedOps() + { + __receiveBuffer = new byte[PACKET_SIZE]; + __receiveDatagram = + new DatagramPacket(__receiveBuffer, __receiveBuffer.length); + _sendBuffer = new byte[PACKET_SIZE]; + __sendDatagram = + new DatagramPacket(_sendBuffer, _sendBuffer.length); + } + + /*** + * Releases the resources used to perform buffered sends and receives. + ***/ + public final void endBufferedOps() + { + __receiveBuffer = null; + __receiveDatagram = null; + _sendBuffer = null; + __sendDatagram = null; + } + + + /*** + * Sends a TFTP packet to its destination. + *

+ * @param packet The TFTP packet to send. + * @exception IOException If some I/O error occurs. + ***/ + public final void send(TFTPPacket packet) throws IOException + { + _socket_.send(packet.newDatagram()); + } + + + /*** + * Receives a TFTPPacket. + *

+ * @return The TFTPPacket received. + * @exception InterruptedIOException If a socket timeout occurs. The + * Java documentation claims an InterruptedIOException is thrown + * on a DatagramSocket timeout, but in practice we find a + * SocketException is thrown. You should catch both to be safe. + * @exception SocketException If a socket timeout occurs. The + * Java documentation claims an InterruptedIOException is thrown + * on a DatagramSocket timeout, but in practice we find a + * SocketException is thrown. You should catch both to be safe. + * @exception IOException If some other I/O error occurs. + * @exception TFTPPacketException If an invalid TFTP packet is received. + ***/ + public final TFTPPacket receive() throws IOException, InterruptedIOException, + SocketException, TFTPPacketException + { + DatagramPacket packet; + + packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE); + + _socket_.receive(packet); + + return TFTPPacket.newTFTPPacket(packet); + } + + +} diff --git a/org/apache/commons/net/tftp/TFTPAckPacket.java b/org/apache/commons/net/tftp/TFTPAckPacket.java new file mode 100644 index 0000000..a0fe7f9 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPAckPacket.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * A final class derived from TFTPPacket definiing the TFTP Acknowledgement + * packet type. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTPPacketException + * @see TFTP + ***/ + +public final class TFTPAckPacket extends TFTPPacket +{ + /*** The block number being acknowledged by the packet. ***/ + int _blockNumber; + + /*** + * Creates an acknowledgment packet to be sent to a host at a given port + * acknowledging receipt of a block. + *

+ * @param destination The host to which the packet is going to be sent. + * @param port The port to which the packet is going to be sent. + * @param blockNumber The block number being acknowledged. + ***/ + public TFTPAckPacket(InetAddress destination, int port, int blockNumber) + { + super(TFTPPacket.ACKNOWLEDGEMENT, destination, port); + _blockNumber = blockNumber; + } + + /*** + * Creates an acknowledgement packet based from a received + * datagram. Assumes the datagram is at least length 4, else an + * ArrayIndexOutOfBoundsException may be thrown. + *

+ * @param datagram The datagram containing the received acknowledgement. + * @throws TFTPPacketException If the datagram isn't a valid TFTP + * acknowledgement packet. + ***/ + TFTPAckPacket(DatagramPacket datagram) throws TFTPPacketException + { + super(TFTPPacket.ACKNOWLEDGEMENT, datagram.getAddress(), + datagram.getPort()); + byte[] data; + + data = datagram.getData(); + + if (getType() != data[1]) + throw new TFTPPacketException("TFTP operator code does not match type."); + + _blockNumber = (((data[2] & 0xff) << 8) | (data[3] & 0xff)); + } + + /*** + * This is a method only available within the package for + * implementing efficient datagram transport by elminating buffering. + * It takes a datagram as an argument, and a byte buffer in which + * to store the raw datagram data. Inside the method, the data + * is set as the datagram's data and the datagram returned. + *

+ * @param datagram The datagram to create. + * @param data The buffer to store the packet and to use in the datagram. + * @return The datagram argument. + ***/ + @Override + DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) + { + data[0] = 0; + data[1] = (byte)_type; + data[2] = (byte)((_blockNumber & 0xffff) >> 8); + data[3] = (byte)(_blockNumber & 0xff); + + datagram.setAddress(_address); + datagram.setPort(_port); + datagram.setData(data); + datagram.setLength(4); + + return datagram; + } + + + /*** + * Creates a UDP datagram containing all the TFTP + * acknowledgement packet data in the proper format. + * This is a method exposed to the programmer in case he + * wants to implement his own TFTP client instead of using + * the {@link org.apache.commons.net.tftp.TFTPClient} + * class. Under normal circumstances, you should not have a need to call this + * method. + *

+ * @return A UDP datagram containing the TFTP acknowledgement packet. + ***/ + @Override + public DatagramPacket newDatagram() + { + byte[] data; + + data = new byte[4]; + data[0] = 0; + data[1] = (byte)_type; + data[2] = (byte)((_blockNumber & 0xffff) >> 8); + data[3] = (byte)(_blockNumber & 0xff); + + return new DatagramPacket(data, data.length, _address, _port); + } + + + /*** + * Returns the block number of the acknowledgement. + *

+ * @return The block number of the acknowledgement. + ***/ + public int getBlockNumber() + { + return _blockNumber; + } + + + /*** Sets the block number of the acknowledgement. ***/ + public void setBlockNumber(int blockNumber) + { + _blockNumber = blockNumber; + } +} + diff --git a/org/apache/commons/net/tftp/TFTPClient.java b/org/apache/commons/net/tftp/TFTPClient.java new file mode 100644 index 0000000..71d4ec6 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPClient.java @@ -0,0 +1,610 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import org.apache.commons.net.io.FromNetASCIIOutputStream; +import org.apache.commons.net.io.ToNetASCIIInputStream; + +/*** + * The TFTPClient class encapsulates all the aspects of the TFTP protocol + * necessary to receive and send files through TFTP. It is derived from + * the {@link org.apache.commons.net.tftp.TFTP} because + * it is more convenient than using aggregation, and as a result exposes + * the same set of methods to allow you to deal with the TFTP protocol + * directly. However, almost every user should only be concerend with the + * the {@link org.apache.commons.net.DatagramSocketClient#open open() }, + * {@link org.apache.commons.net.DatagramSocketClient#close close() }, + * {@link #sendFile sendFile() }, and + * {@link #receiveFile receiveFile() } methods. Additionally, the + * {@link #setMaxTimeouts setMaxTimeouts() } and + * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() } + * methods may be of importance for performance + * tuning. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTP + * @see TFTPPacket + * @see TFTPPacketException + ***/ + +public class TFTPClient extends TFTP +{ + /*** + * The default number of times a receive attempt is allowed to timeout + * before ending attempts to retry the receive and failing. The default + * is 5 timeouts. + ***/ + public static final int DEFAULT_MAX_TIMEOUTS = 5; + + /*** The maximum number of timeouts allowed before failing. ***/ + private int __maxTimeouts; + + /*** + * Creates a TFTPClient instance with a default timeout of DEFAULT_TIMEOUT, + * maximum timeouts value of DEFAULT_MAX_TIMEOUTS, a null socket, + * and buffered operations disabled. + ***/ + public TFTPClient() + { + __maxTimeouts = DEFAULT_MAX_TIMEOUTS; + } + + /*** + * Sets the maximum number of times a receive attempt is allowed to + * timeout during a receiveFile() or sendFile() operation before ending + * attempts to retry the receive and failing. + * The default is DEFAULT_MAX_TIMEOUTS. + *

+ * @param numTimeouts The maximum number of timeouts to allow. Values + * less than 1 should not be used, but if they are, they are + * treated as 1. + ***/ + public void setMaxTimeouts(int numTimeouts) + { + if (numTimeouts < 1) + __maxTimeouts = 1; + else + __maxTimeouts = numTimeouts; + } + + /*** + * Returns the maximum number of times a receive attempt is allowed to + * timeout before ending attempts to retry the receive and failing. + *

+ * @return The maximum number of timeouts allowed. + ***/ + public int getMaxTimeouts() + { + return __maxTimeouts; + } + + + /*** + * Requests a named file from a remote host, writes the + * file to an OutputStream, closes the connection, and returns the number + * of bytes read. A local UDP socket must first be created by + * {@link org.apache.commons.net.DatagramSocketClient#open open()} before + * invoking this method. This method will not close the OutputStream + * containing the file; you must close it after the method invocation. + *

+ * @param filename The name of the file to receive. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param output The OutputStream to which the file should be written. + * @param host The remote host serving the file. + * @param port The port number of the remote TFTP server. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + ***/ + public int receiveFile(String filename, int mode, OutputStream output, + InetAddress host, int port) throws IOException + { + int bytesRead, timeouts, lastBlock, block, hostPort, dataLength; + TFTPPacket sent, received = null; + TFTPErrorPacket error; + TFTPDataPacket data; + TFTPAckPacket ack = new TFTPAckPacket(host, port, 0); + + beginBufferedOps(); + + dataLength = lastBlock = hostPort = bytesRead = 0; + block = 1; + + if (mode == TFTP.ASCII_MODE) + output = new FromNetASCIIOutputStream(output); + + sent = + new TFTPReadRequestPacket(host, port, filename, mode); + +_sendPacket: + do + { + bufferedSend(sent); + +_receivePacket: + while (true) + { + timeouts = 0; + while (timeouts < __maxTimeouts) + { + try + { + received = bufferedReceive(); + break; + } + catch (SocketException e) + { + if (++timeouts >= __maxTimeouts) + { + endBufferedOps(); + throw new IOException("Connection timed out."); + } + continue; + } + catch (InterruptedIOException e) + { + if (++timeouts >= __maxTimeouts) + { + endBufferedOps(); + throw new IOException("Connection timed out."); + } + continue; + } + catch (TFTPPacketException e) + { + endBufferedOps(); + throw new IOException("Bad packet: " + e.getMessage()); + } + } + + // The first time we receive we get the port number and + // answering host address (for hosts with multiple IPs) + if (lastBlock == 0) + { + hostPort = received.getPort(); + ack.setPort(hostPort); + if(!host.equals(received.getAddress())) + { + host = received.getAddress(); + ack.setAddress(host); + sent.setAddress(host); + } + } + + // Comply with RFC 783 indication that an error acknowledgement + // should be sent to originator if unexpected TID or host. + if (host.equals(received.getAddress()) && + received.getPort() == hostPort) + { + + switch (received.getType()) + { + case TFTPPacket.ERROR: + error = (TFTPErrorPacket)received; + endBufferedOps(); + throw new IOException("Error code " + error.getError() + + " received: " + error.getMessage()); + case TFTPPacket.DATA: + data = (TFTPDataPacket)received; + dataLength = data.getDataLength(); + + lastBlock = data.getBlockNumber(); + + if (lastBlock == block) + { + try + { + output.write(data.getData(), data.getDataOffset(), + dataLength); + } + catch (IOException e) + { + error = new TFTPErrorPacket(host, hostPort, + TFTPErrorPacket.OUT_OF_SPACE, + "File write failed."); + bufferedSend(error); + endBufferedOps(); + throw e; + } + ++block; + if (block > 65535) + { + // wrap the block number + block = 0; + } + + break _receivePacket; + } + else + { + discardPackets(); + + if (lastBlock == (block == 0 ? 65535 : (block - 1))) + continue _sendPacket; // Resend last acknowledgement. + + continue _receivePacket; // Start fetching packets again. + } + //break; + + default: + endBufferedOps(); + throw new IOException("Received unexpected packet type."); + } + } + else + { + error = new TFTPErrorPacket(received.getAddress(), + received.getPort(), + TFTPErrorPacket.UNKNOWN_TID, + "Unexpected host or port."); + bufferedSend(error); + continue _sendPacket; + } + + // We should never get here, but this is a safety to avoid + // infinite loop. If only Java had the goto statement. + //break; + } + + ack.setBlockNumber(lastBlock); + sent = ack; + bytesRead += dataLength; + } // First data packet less than 512 bytes signals end of stream. + + while (dataLength == TFTPPacket.SEGMENT_SIZE); + + bufferedSend(sent); + endBufferedOps(); + + return bytesRead; + } + + + /*** + * Requests a named file from a remote host, writes the + * file to an OutputStream, closes the connection, and returns the number + * of bytes read. A local UDP socket must first be created by + * {@link org.apache.commons.net.DatagramSocketClient#open open()} before + * invoking this method. This method will not close the OutputStream + * containing the file; you must close it after the method invocation. + *

+ * @param filename The name of the file to receive. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param output The OutputStream to which the file should be written. + * @param hostname The name of the remote host serving the file. + * @param port The port number of the remote TFTP server. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + public int receiveFile(String filename, int mode, OutputStream output, + String hostname, int port) + throws UnknownHostException, IOException + { + return receiveFile(filename, mode, output, InetAddress.getByName(hostname), + port); + } + + + /*** + * Same as calling receiveFile(filename, mode, output, host, TFTP.DEFAULT_PORT). + * + * @param filename The name of the file to receive. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param output The OutputStream to which the file should be written. + * @param host The remote host serving the file. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + ***/ + public int receiveFile(String filename, int mode, OutputStream output, + InetAddress host) + throws IOException + { + return receiveFile(filename, mode, output, host, DEFAULT_PORT); + } + + /*** + * Same as calling receiveFile(filename, mode, output, hostname, TFTP.DEFAULT_PORT). + * + * @param filename The name of the file to receive. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param output The OutputStream to which the file should be written. + * @param hostname The name of the remote host serving the file. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + public int receiveFile(String filename, int mode, OutputStream output, + String hostname) + throws UnknownHostException, IOException + { + return receiveFile(filename, mode, output, InetAddress.getByName(hostname), + DEFAULT_PORT); + } + + + /*** + * Requests to send a file to a remote host, reads the file from an + * InputStream, sends the file to the remote host, and closes the + * connection. A local UDP socket must first be created by + * {@link org.apache.commons.net.DatagramSocketClient#open open()} before + * invoking this method. This method will not close the InputStream + * containing the file; you must close it after the method invocation. + *

+ * @param filename The name the remote server should use when creating + * the file on its file system. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param host The remote host receiving the file. + * @param port The port number of the remote TFTP server. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + ***/ + public void sendFile(String filename, int mode, InputStream input, + InetAddress host, int port) throws IOException + { + int bytesRead, timeouts, lastBlock, block, hostPort, dataLength, offset, totalThisPacket; + TFTPPacket sent, received = null; + TFTPErrorPacket error; + TFTPDataPacket data = + new TFTPDataPacket(host, port, 0, _sendBuffer, 4, 0); + TFTPAckPacket ack; + + boolean justStarted = true; + + beginBufferedOps(); + + dataLength = lastBlock = hostPort = bytesRead = totalThisPacket = 0; + block = 0; + boolean lastAckWait = false; + + if (mode == TFTP.ASCII_MODE) + input = new ToNetASCIIInputStream(input); + + sent = + new TFTPWriteRequestPacket(host, port, filename, mode); + +_sendPacket: + do + { + // first time: block is 0, lastBlock is 0, send a request packet. + // subsequent: block is integer starting at 1, send data packet. + bufferedSend(sent); + + // this is trying to receive an ACK +_receivePacket: + while (true) + { + + + timeouts = 0; + while (timeouts < __maxTimeouts) + { + try + { + received = bufferedReceive(); + break; + } + catch (SocketException e) + { + if (++timeouts >= __maxTimeouts) + { + endBufferedOps(); + throw new IOException("Connection timed out."); + } + continue; + } + catch (InterruptedIOException e) + { + if (++timeouts >= __maxTimeouts) + { + endBufferedOps(); + throw new IOException("Connection timed out."); + } + continue; + } + catch (TFTPPacketException e) + { + endBufferedOps(); + throw new IOException("Bad packet: " + e.getMessage()); + } + } // end of while loop over tries to receive + + // The first time we receive we get the port number and + // answering host address (for hosts with multiple IPs) + if (justStarted) + { + justStarted = false; + hostPort = received.getPort(); + data.setPort(hostPort); + if(!host.equals(received.getAddress())) + { + host = received.getAddress(); + data.setAddress(host); + sent.setAddress(host); + } + } + + // Comply with RFC 783 indication that an error acknowledgement + // should be sent to originator if unexpected TID or host. + if (host.equals(received.getAddress()) && + received.getPort() == hostPort) + { + + switch (received.getType()) + { + case TFTPPacket.ERROR: + error = (TFTPErrorPacket)received; + endBufferedOps(); + throw new IOException("Error code " + error.getError() + + " received: " + error.getMessage()); + case TFTPPacket.ACKNOWLEDGEMENT: + ack = (TFTPAckPacket)received; + + lastBlock = ack.getBlockNumber(); + + if (lastBlock == block) + { + ++block; + if (block > 65535) + { + // wrap the block number + block = 0; + } + if (lastAckWait) { + + break _sendPacket; + } + else { + break _receivePacket; + } + } + else + { + discardPackets(); + + if (lastBlock == (block == 0 ? 65535 : (block - 1))) + continue _sendPacket; // Resend last acknowledgement. + + continue _receivePacket; // Start fetching packets again. + } + //break; + + default: + endBufferedOps(); + throw new IOException("Received unexpected packet type."); + } + } + else + { + error = new TFTPErrorPacket(received.getAddress(), + received.getPort(), + TFTPErrorPacket.UNKNOWN_TID, + "Unexpected host or port."); + bufferedSend(error); + continue _sendPacket; + } + + // We should never get here, but this is a safety to avoid + // infinite loop. If only Java had the goto statement. + //break; + } + + // OK, we have just gotten ACK about the last data we sent. Make another + // and send it + + dataLength = TFTPPacket.SEGMENT_SIZE; + offset = 4; + totalThisPacket = 0; + while (dataLength > 0 && + (bytesRead = input.read(_sendBuffer, offset, dataLength)) > 0) + { + offset += bytesRead; + dataLength -= bytesRead; + totalThisPacket += bytesRead; + } + + if( totalThisPacket < TFTPPacket.SEGMENT_SIZE ) { + /* this will be our last packet -- send, wait for ack, stop */ + lastAckWait = true; + } + data.setBlockNumber(block); + data.setData(_sendBuffer, 4, totalThisPacket); + sent = data; + } + while ( totalThisPacket > 0 || lastAckWait ); + // Note: this was looping while dataLength == 0 || lastAckWait, + // which was discarding the last packet if it was not full size + // Should send the packet. + + endBufferedOps(); + } + + + /*** + * Requests to send a file to a remote host, reads the file from an + * InputStream, sends the file to the remote host, and closes the + * connection. A local UDP socket must first be created by + * {@link org.apache.commons.net.DatagramSocketClient#open open()} before + * invoking this method. This method will not close the InputStream + * containing the file; you must close it after the method invocation. + *

+ * @param filename The name the remote server should use when creating + * the file on its file system. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param hostname The name of the remote host receiving the file. + * @param port The port number of the remote TFTP server. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + public void sendFile(String filename, int mode, InputStream input, + String hostname, int port) + throws UnknownHostException, IOException + { + sendFile(filename, mode, input, InetAddress.getByName(hostname), port); + } + + + /*** + * Same as calling sendFile(filename, mode, input, host, TFTP.DEFAULT_PORT). + * + * @param filename The name the remote server should use when creating + * the file on its file system. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param host The name of the remote host receiving the file. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + public void sendFile(String filename, int mode, InputStream input, + InetAddress host) + throws IOException + { + sendFile(filename, mode, input, host, DEFAULT_PORT); + } + + /*** + * Same as calling sendFile(filename, mode, input, hostname, TFTP.DEFAULT_PORT). + * + * @param filename The name the remote server should use when creating + * the file on its file system. + * @param mode The TFTP mode of the transfer (one of the MODE constants). + * @param hostname The name of the remote host receiving the file. + * @exception IOException If an I/O error occurs. The nature of the + * error will be reported in the message. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + public void sendFile(String filename, int mode, InputStream input, + String hostname) + throws UnknownHostException, IOException + { + sendFile(filename, mode, input, InetAddress.getByName(hostname), + DEFAULT_PORT); + } +} diff --git a/org/apache/commons/net/tftp/TFTPDataPacket.java b/org/apache/commons/net/tftp/TFTPDataPacket.java new file mode 100644 index 0000000..24c0dd3 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPDataPacket.java @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * A final class derived from TFTPPacket definiing the TFTP Data + * packet type. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTPPacketException + * @see TFTP + ***/ + +public final class TFTPDataPacket extends TFTPPacket +{ + /*** The maximum number of bytes in a TFTP data packet (512) ***/ + public static final int MAX_DATA_LENGTH = 512; + + /*** The minimum number of bytes in a TFTP data packet (0) ***/ + public static final int MIN_DATA_LENGTH = 0; + + /*** The block number of the packet. ***/ + int _blockNumber; + + /*** The length of the data. ***/ + int _length; + + /*** The offset into the _data array at which the data begins. ***/ + int _offset; + + /*** The data stored in the packet. ***/ + byte[] _data; + + /*** + * Creates a data packet to be sent to a host at a given port + * with a given block number. The actual data to be sent is passed as + * an array, an offset, and a length. The offset is the offset into + * the byte array where the data starts. The length is the length of + * the data. If the length is greater than MAX_DATA_LENGTH, it is + * truncated. + *

+ * @param destination The host to which the packet is going to be sent. + * @param port The port to which the packet is going to be sent. + * @param blockNumber The block number of the data. + * @param data The byte array containing the data. + * @param offset The offset into the array where the data starts. + * @param length The length of the data. + ***/ + public TFTPDataPacket(InetAddress destination, int port, int blockNumber, + byte[] data, int offset, int length) + { + super(TFTPPacket.DATA, destination, port); + + _blockNumber = blockNumber; + _data = data; + _offset = offset; + + if (length > MAX_DATA_LENGTH) + _length = MAX_DATA_LENGTH; + else + _length = length; + } + + public TFTPDataPacket(InetAddress destination, int port, int blockNumber, + byte[] data) + { + this(destination, port, blockNumber, data, 0, data.length); + } + + + /*** + * Creates a data packet based from a received + * datagram. Assumes the datagram is at least length 4, else an + * ArrayIndexOutOfBoundsException may be thrown. + *

+ * @param datagram The datagram containing the received data. + * @throws TFTPPacketException If the datagram isn't a valid TFTP + * data packet. + ***/ + TFTPDataPacket(DatagramPacket datagram) throws TFTPPacketException + { + super(TFTPPacket.DATA, datagram.getAddress(), datagram.getPort()); + + _data = datagram.getData(); + _offset = 4; + + if (getType() != _data[1]) + throw new TFTPPacketException("TFTP operator code does not match type."); + + _blockNumber = (((_data[2] & 0xff) << 8) | (_data[3] & 0xff)); + + _length = datagram.getLength() - 4; + + if (_length > MAX_DATA_LENGTH) + _length = MAX_DATA_LENGTH; + } + + /*** + * This is a method only available within the package for + * implementing efficient datagram transport by elminating buffering. + * It takes a datagram as an argument, and a byte buffer in which + * to store the raw datagram data. Inside the method, the data + * is set as the datagram's data and the datagram returned. + *

+ * @param datagram The datagram to create. + * @param data The buffer to store the packet and to use in the datagram. + * @return The datagram argument. + ***/ + @Override + DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) + { + data[0] = 0; + data[1] = (byte)_type; + data[2] = (byte)((_blockNumber & 0xffff) >> 8); + data[3] = (byte)(_blockNumber & 0xff); + + // Doublecheck we're not the same + if (data != _data) + System.arraycopy(_data, _offset, data, 4, _length); + + datagram.setAddress(_address); + datagram.setPort(_port); + datagram.setData(data); + datagram.setLength(_length + 4); + + return datagram; + } + + /*** + * Creates a UDP datagram containing all the TFTP + * data packet data in the proper format. + * This is a method exposed to the programmer in case he + * wants to implement his own TFTP client instead of using + * the {@link org.apache.commons.net.tftp.TFTPClient} + * class. + * Under normal circumstances, you should not have a need to call this + * method. + *

+ * @return A UDP datagram containing the TFTP data packet. + ***/ + @Override + public DatagramPacket newDatagram() + { + byte[] data; + + data = new byte[_length + 4]; + data[0] = 0; + data[1] = (byte)_type; + data[2] = (byte)((_blockNumber & 0xffff) >> 8); + data[3] = (byte)(_blockNumber & 0xff); + + System.arraycopy(_data, _offset, data, 4, _length); + + return new DatagramPacket(data, _length + 4, _address, _port); + } + + /*** + * Returns the block number of the data packet. + *

+ * @return The block number of the data packet. + ***/ + public int getBlockNumber() + { + return _blockNumber; + } + + /*** Sets the block number of the data packet. ***/ + public void setBlockNumber(int blockNumber) + { + _blockNumber = blockNumber; + } + + /*** + * Sets the data for the data packet. + *

+ * @param data The byte array containing the data. + * @param offset The offset into the array where the data starts. + * @param length The length of the data. + ***/ + public void setData(byte[] data, int offset, int length) + { + _data = data; + _offset = offset; + _length = length; + + if (length > MAX_DATA_LENGTH) + _length = MAX_DATA_LENGTH; + else + _length = length; + } + + /*** + * Returns the length of the data part of the data packet. + *

+ * @return The length of the data part of the data packet. + ***/ + public int getDataLength() + { + return _length; + } + + /*** + * Returns the offset into the byte array where the packet data actually + * starts. + *

+ * @return The offset into the byte array where the packet data actually + * starts. + ***/ + public int getDataOffset() + { + return _offset; + } + + /*** + * Returns the byte array containing the packet data. + *

+ * @return The byte array containing the packet data. + ***/ + public byte[] getData() + { + return _data; + } +} diff --git a/org/apache/commons/net/tftp/TFTPErrorPacket.java b/org/apache/commons/net/tftp/TFTPErrorPacket.java new file mode 100644 index 0000000..2e7aec2 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPErrorPacket.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * A final class derived from TFTPPacket definiing the TFTP Error + * packet type. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTPPacketException + * @see TFTP + ***/ + +public final class TFTPErrorPacket extends TFTPPacket +{ + /*** The undefined error code according to RFC 783, value 0. ***/ + public static final int UNDEFINED = 0; + + /*** The file not found error code according to RFC 783, value 1. ***/ + public static final int FILE_NOT_FOUND = 1; + + /*** The access violation error code according to RFC 783, value 2. ***/ + public static final int ACCESS_VIOLATION = 2; + + /*** The disk full error code according to RFC 783, value 3. ***/ + public static final int OUT_OF_SPACE = 3; + + /*** + * The illegal TFTP operation error code according to RFC 783, value 4. + ***/ + public static final int ILLEGAL_OPERATION = 4; + + /*** The unknown transfer id error code according to RFC 783, value 5. ***/ + public static final int UNKNOWN_TID = 5; + + /*** The file already exists error code according to RFC 783, value 6. ***/ + public static final int FILE_EXISTS = 6; + + /*** The no such user error code according to RFC 783, value 7. ***/ + public static final int NO_SUCH_USER = 7; + + /*** The error code of this packet. ***/ + int _error; + + /*** The error message of this packet. ***/ + String _message; + + /*** + * Creates an error packet to be sent to a host at a given port + * with an error code and error message. + *

+ * @param destination The host to which the packet is going to be sent. + * @param port The port to which the packet is going to be sent. + * @param error The error code of the packet. + * @param message The error message of the packet. + ***/ + public TFTPErrorPacket(InetAddress destination, int port, + int error, String message) + { + super(TFTPPacket.ERROR, destination, port); + + _error = error; + _message = message; + } + + /*** + * Creates an error packet based from a received + * datagram. Assumes the datagram is at least length 4, else an + * ArrayIndexOutOfBoundsException may be thrown. + *

+ * @param datagram The datagram containing the received error. + * @throws TFTPPacketException If the datagram isn't a valid TFTP + * error packet. + ***/ + TFTPErrorPacket(DatagramPacket datagram) throws TFTPPacketException + { + super(TFTPPacket.ERROR, datagram.getAddress(), datagram.getPort()); + int index, length; + byte[] data; + StringBuffer buffer; + + data = datagram.getData(); + length = datagram.getLength(); + + if (getType() != data[1]) + throw new TFTPPacketException("TFTP operator code does not match type."); + + _error = (((data[2] & 0xff) << 8) | (data[3] & 0xff)); + + if (length < 5) + throw new TFTPPacketException("Bad error packet. No message."); + + index = 4; + buffer = new StringBuffer(); + + while (index < length && data[index] != 0) + { + buffer.append((char)data[index]); + ++index; + } + + _message = buffer.toString(); + } + + /*** + * This is a method only available within the package for + * implementing efficient datagram transport by elminating buffering. + * It takes a datagram as an argument, and a byte buffer in which + * to store the raw datagram data. Inside the method, the data + * is set as the datagram's data and the datagram returned. + *

+ * @param datagram The datagram to create. + * @param data The buffer to store the packet and to use in the datagram. + * @return The datagram argument. + ***/ + @Override + DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) + { + int length; + + length = _message.length(); + + data[0] = 0; + data[1] = (byte)_type; + data[2] = (byte)((_error & 0xffff) >> 8); + data[3] = (byte)(_error & 0xff); + + System.arraycopy(_message.getBytes(), 0, data, 4, length); + + data[length + 4] = 0; + + datagram.setAddress(_address); + datagram.setPort(_port); + datagram.setData(data); + datagram.setLength(length + 4); + + return datagram; + } + + + /*** + * Creates a UDP datagram containing all the TFTP + * error packet data in the proper format. + * This is a method exposed to the programmer in case he + * wants to implement his own TFTP client instead of using + * the {@link org.apache.commons.net.tftp.TFTPClient} + * class. + * Under normal circumstances, you should not have a need to call this + * method. + *

+ * @return A UDP datagram containing the TFTP error packet. + ***/ + @Override + public DatagramPacket newDatagram() + { + byte[] data; + int length; + + length = _message.length(); + + data = new byte[length + 5]; + data[0] = 0; + data[1] = (byte)_type; + data[2] = (byte)((_error & 0xffff) >> 8); + data[3] = (byte)(_error & 0xff); + + System.arraycopy(_message.getBytes(), 0, data, 4, length); + + data[length + 4] = 0; + + return new DatagramPacket(data, data.length, _address, _port); + } + + + /*** + * Returns the error code of the packet. + *

+ * @return The error code of the packet. + ***/ + public int getError() + { + return _error; + } + + + /*** + * Returns the error message of the packet. + *

+ * @return The error message of the packet. + ***/ + public String getMessage() + { + return _message; + } +} diff --git a/org/apache/commons/net/tftp/TFTPPacket.java b/org/apache/commons/net/tftp/TFTPPacket.java new file mode 100644 index 0000000..e1dc5f1 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPPacket.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * TFTPPacket is an abstract class encapsulating the functionality common + * to the 5 types of TFTP packets. It also provides a static factory + * method that will create the correct TFTP packet instance from a + * datagram. This relieves the programmer from having to figure out what + * kind of TFTP packet is contained in a datagram and create it himself. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacketException + * @see TFTP + ***/ + +public abstract class TFTPPacket +{ + /*** + * The minimum size of a packet. This is 4 bytes. It is enough + * to store the opcode and blocknumber or other required data + * depending on the packet type. + ***/ + static final int MIN_PACKET_SIZE = 4; + + /*** + * This is the actual TFTP spec + * identifier and is equal to 1. + * Identifier returned by {@link #getType getType()} + * indicating a read request packet. + ***/ + public static final int READ_REQUEST = 1; + + /*** + * This is the actual TFTP spec + * identifier and is equal to 2. + * Identifier returned by {@link #getType getType()} + * indicating a write request packet. + ***/ + public static final int WRITE_REQUEST = 2; + + /*** + * This is the actual TFTP spec + * identifier and is equal to 3. + * Identifier returned by {@link #getType getType()} + * indicating a data packet. + ***/ + public static final int DATA = 3; + + /*** + * This is the actual TFTP spec + * identifier and is equal to 4. + * Identifier returned by {@link #getType getType()} + * indicating an acknowledgement packet. + ***/ + public static final int ACKNOWLEDGEMENT = 4; + + /*** + * This is the actual TFTP spec + * identifier and is equal to 5. + * Identifier returned by {@link #getType getType()} + * indicating an error packet. + ***/ + public static final int ERROR = 5; + + /*** + * The TFTP data packet maximum segment size in bytes. This is 512 + * and is useful for those familiar with the TFTP protocol who want + * to use the {@link org.apache.commons.net.tftp.TFTP} + * class methods to implement their own TFTP servers or clients. + ***/ + public static final int SEGMENT_SIZE = 512; + + /*** The type of packet. ***/ + int _type; + + /*** The port the packet came from or is going to. ***/ + int _port; + + /*** The host the packet is going to be sent or where it came from. ***/ + InetAddress _address; + + /*** + * When you receive a datagram that you expect to be a TFTP packet, you use + * this factory method to create the proper TFTPPacket object + * encapsulating the data contained in that datagram. This method is the + * only way you can instantiate a TFTPPacket derived class from a + * datagram. + *

+ * @param datagram The datagram containing a TFTP packet. + * @return The TFTPPacket object corresponding to the datagram. + * @exception TFTPPacketException If the datagram does not contain a valid + * TFTP packet. + ***/ + public final static TFTPPacket newTFTPPacket(DatagramPacket datagram) + throws TFTPPacketException + { + byte[] data; + TFTPPacket packet = null; + + if (datagram.getLength() < MIN_PACKET_SIZE) + throw new TFTPPacketException( + "Bad packet. Datagram data length is too short."); + + data = datagram.getData(); + + switch (data[1]) + { + case READ_REQUEST: + packet = new TFTPReadRequestPacket(datagram); + break; + case WRITE_REQUEST: + packet = new TFTPWriteRequestPacket(datagram); + break; + case DATA: + packet = new TFTPDataPacket(datagram); + break; + case ACKNOWLEDGEMENT: + packet = new TFTPAckPacket(datagram); + break; + case ERROR: + packet = new TFTPErrorPacket(datagram); + break; + default: + throw new TFTPPacketException( + "Bad packet. Invalid TFTP operator code."); + } + + return packet; + } + + /*** + * This constructor is not visible outside of the package. It is used + * by subclasses within the package to initialize base data. + *

+ * @param type The type of the packet. + * @param address The host the packet came from or is going to be sent. + * @param port The port the packet came from or is going to be sent. + **/ + TFTPPacket(int type, InetAddress address, int port) + { + _type = type; + _address = address; + _port = port; + } + + /*** + * This is an abstract method only available within the package for + * implementing efficient datagram transport by elminating buffering. + * It takes a datagram as an argument, and a byte buffer in which + * to store the raw datagram data. Inside the method, the data + * should be set as the datagram's data and the datagram returned. + *

+ * @param datagram The datagram to create. + * @param data The buffer to store the packet and to use in the datagram. + * @return The datagram argument. + ***/ + abstract DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data); + + /*** + * Creates a UDP datagram containing all the TFTP packet + * data in the proper format. + * This is an abstract method, exposed to the programmer in case he + * wants to implement his own TFTP client instead of using + * the {@link org.apache.commons.net.tftp.TFTPClient} + * class. + * Under normal circumstances, you should not have a need to call this + * method. + *

+ * @return A UDP datagram containing the TFTP packet. + ***/ + public abstract DatagramPacket newDatagram(); + + /*** + * Returns the type of the packet. + *

+ * @return The type of the packet. + ***/ + public final int getType() + { + return _type; + } + + /*** + * Returns the address of the host where the packet is going to be sent + * or where it came from. + *

+ * @return The type of the packet. + ***/ + public final InetAddress getAddress() + { + return _address; + } + + /*** + * Returns the port where the packet is going to be sent + * or where it came from. + *

+ * @return The port where the packet came from or where it is going. + ***/ + public final int getPort() + { + return _port; + } + + /*** Sets the port where the packet is going to be sent. ***/ + public final void setPort(int port) + { + _port = port; + } + + /*** Sets the host address where the packet is going to be sent. ***/ + public final void setAddress(InetAddress address) + { + _address = address; + } +} diff --git a/org/apache/commons/net/tftp/TFTPPacketException.java b/org/apache/commons/net/tftp/TFTPPacketException.java new file mode 100644 index 0000000..286fa3a --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPPacketException.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +/*** + * A class used to signify the occurrence of an error in the creation of + * a TFTP packet. It is not declared final so that it may be subclassed + * to identify more specific errors. You would only want to do this if + * you were building your own TFTP client or server on top of the + * {@link org.apache.commons.net.tftp.TFTP} + * class if you + * wanted more functionality than the + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods provide. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTP + ***/ + +public class TFTPPacketException extends Exception +{ + + /*** + * Simply calls the corresponding constructor of its superclass. + ***/ + public TFTPPacketException() + { + super(); + } + + /*** + * Simply calls the corresponding constructor of its superclass. + ***/ + public TFTPPacketException(String message) + { + super(message); + } +} diff --git a/org/apache/commons/net/tftp/TFTPReadRequestPacket.java b/org/apache/commons/net/tftp/TFTPReadRequestPacket.java new file mode 100644 index 0000000..2669df6 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPReadRequestPacket.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * A class derived from TFTPRequestPacket definiing a TFTP read request + * packet type. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTPRequestPacket + * @see TFTPPacketException + * @see TFTP + ***/ + +public final class TFTPReadRequestPacket extends TFTPRequestPacket +{ + + /*** + * Creates a read request packet to be sent to a host at a + * given port with a filename and transfer mode request. + *

+ * @param destination The host to which the packet is going to be sent. + * @param port The port to which the packet is going to be sent. + * @param filename The requested filename. + * @param mode The requested transfer mode. This should be on of the TFTP + * class MODE constants (e.g., TFTP.NETASCII_MODE). + ***/ + public TFTPReadRequestPacket(InetAddress destination, int port, + String filename, int mode) + { + super(destination, port, TFTPPacket.READ_REQUEST, filename, mode); + } + + /*** + * Creates a read request packet of based on a received + * datagram and assumes the datagram has already been identified as a + * read request. Assumes the datagram is at least length 4, else an + * ArrayIndexOutOfBoundsException may be thrown. + *

+ * @param datagram The datagram containing the received request. + * @throws TFTPPacketException If the datagram isn't a valid TFTP + * request packet. + ***/ + TFTPReadRequestPacket(DatagramPacket datagram) throws TFTPPacketException + { + super(TFTPPacket.READ_REQUEST, datagram); + } + +} diff --git a/org/apache/commons/net/tftp/TFTPRequestPacket.java b/org/apache/commons/net/tftp/TFTPRequestPacket.java new file mode 100644 index 0000000..a0f4407 --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPRequestPacket.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * An abstract class derived from TFTPPacket definiing a TFTP Request + * packet type. It is subclassed by the + * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket} + * and + * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket} + * classes. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTPReadRequestPacket + * @see TFTPWriteRequestPacket + * @see TFTPPacketException + * @see TFTP + ***/ + +public abstract class TFTPRequestPacket extends TFTPPacket +{ + /*** + * An array containing the string names of the transfer modes and indexed + * by the transfer mode constants. + ***/ + static final String[] _modeStrings = { "netascii", "octet" }; + + /*** + * A null terminated byte array representation of the ascii names of the + * transfer mode constants. This is convenient for creating the TFTP + * request packets. + ***/ + static final byte[] _modeBytes[] = { + { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c', + (byte)'i', (byte)'i', 0 }, + { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 } + }; + + /*** The transfer mode of the request. ***/ + int _mode; + + /*** The filename of the request. ***/ + String _filename; + + /*** + * Creates a request packet of a given type to be sent to a host at a + * given port with a filename and transfer mode request. + *

+ * @param destination The host to which the packet is going to be sent. + * @param port The port to which the packet is going to be sent. + * @param type The type of the request (either TFTPPacket.READ_REQUEST or + * TFTPPacket.WRITE_REQUEST). + * @param filename The requested filename. + * @param mode The requested transfer mode. This should be on of the TFTP + * class MODE constants (e.g., TFTP.NETASCII_MODE). + ***/ + TFTPRequestPacket(InetAddress destination, int port, + int type, String filename, int mode) + { + super(type, destination, port); + + _filename = filename; + _mode = mode; + } + + /*** + * Creates a request packet of a given type based on a received + * datagram. Assumes the datagram is at least length 4, else an + * ArrayIndexOutOfBoundsException may be thrown. + *

+ * @param type The type of the request (either TFTPPacket.READ_REQUEST or + * TFTPPacket.WRITE_REQUEST). + * @param datagram The datagram containing the received request. + * @throws TFTPPacketException If the datagram isn't a valid TFTP + * request packet of the appropriate type. + ***/ + TFTPRequestPacket(int type, DatagramPacket datagram) + throws TFTPPacketException + { + super(type, datagram.getAddress(), datagram.getPort()); + + byte[] data; + int index, length; + String mode; + StringBuffer buffer; + + data = datagram.getData(); + + if (getType() != data[1]) + throw new TFTPPacketException("TFTP operator code does not match type."); + + buffer = new StringBuffer(); + + index = 2; + length = datagram.getLength(); + + while (index < length && data[index] != 0) + { + buffer.append((char)data[index]); + ++index; + } + + _filename = buffer.toString(); + + if (index >= length) + throw new TFTPPacketException("Bad filename and mode format."); + + buffer.setLength(0); + ++index; // need to advance beyond the end of string marker + while (index < length && data[index] != 0) + { + buffer.append((char)data[index]); + ++index; + } + + mode = buffer.toString().toLowerCase(java.util.Locale.ENGLISH); + length = _modeStrings.length; + + for (index = 0; index < length; index++) + { + if (mode.equals(_modeStrings[index])) + { + _mode = index; + break; + } + } + + if (index >= length) + { + throw new TFTPPacketException("Unrecognized TFTP transfer mode: " + mode); + // May just want to default to binary mode instead of throwing + // exception. + //_mode = TFTP.OCTET_MODE; + } + } + + + /*** + * This is a method only available within the package for + * implementing efficient datagram transport by elminating buffering. + * It takes a datagram as an argument, and a byte buffer in which + * to store the raw datagram data. Inside the method, the data + * is set as the datagram's data and the datagram returned. + *

+ * @param datagram The datagram to create. + * @param data The buffer to store the packet and to use in the datagram. + * @return The datagram argument. + ***/ + @Override + final DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) + { + int fileLength, modeLength; + + fileLength = _filename.length(); + modeLength = _modeBytes[_mode].length; + + data[0] = 0; + data[1] = (byte)_type; + System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength); + data[fileLength + 2] = 0; + System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3, + modeLength); + + datagram.setAddress(_address); + datagram.setPort(_port); + datagram.setData(data); + datagram.setLength(fileLength + modeLength + 3); + + return datagram; + } + + /*** + * Creates a UDP datagram containing all the TFTP + * request packet data in the proper format. + * This is a method exposed to the programmer in case he + * wants to implement his own TFTP client instead of using + * the {@link org.apache.commons.net.tftp.TFTPClient} + * class. Under normal circumstances, you should not have a need to call + * this method. + *

+ * @return A UDP datagram containing the TFTP request packet. + ***/ + @Override + public final DatagramPacket newDatagram() + { + int fileLength, modeLength; + byte[] data; + + fileLength = _filename.length(); + modeLength = _modeBytes[_mode].length; + + data = new byte[fileLength + modeLength + 4]; + data[0] = 0; + data[1] = (byte)_type; + System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength); + data[fileLength + 2] = 0; + System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3, + modeLength); + + return new DatagramPacket(data, data.length, _address, _port); + } + + /*** + * Returns the transfer mode of the request. + *

+ * @return The transfer mode of the request. + ***/ + public final int getMode() + { + return _mode; + } + + /*** + * Returns the requested filename. + *

+ * @return The requested filename. + ***/ + public final String getFilename() + { + return _filename; + } +} diff --git a/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java b/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java new file mode 100644 index 0000000..b545b2d --- /dev/null +++ b/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.tftp; + +import java.net.DatagramPacket; +import java.net.InetAddress; + +/*** + * A class derived from TFTPRequestPacket definiing a TFTP write request + * packet type. + *

+ * Details regarding the TFTP protocol and the format of TFTP packets can + * be found in RFC 783. But the point of these classes is to keep you + * from having to worry about the internals. Additionally, only very + * few people should have to care about any of the TFTPPacket classes + * or derived classes. Almost all users should only be concerned with the + * {@link org.apache.commons.net.tftp.TFTPClient} class + * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} + * and + * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} + * methods. + *

+ *

+ * @author Daniel F. Savarese + * @see TFTPPacket + * @see TFTPRequestPacket + * @see TFTPPacketException + * @see TFTP + ***/ + +public final class TFTPWriteRequestPacket extends TFTPRequestPacket +{ + + /*** + * Creates a write request packet to be sent to a host at a + * given port with a filename and transfer mode request. + *

+ * @param destination The host to which the packet is going to be sent. + * @param port The port to which the packet is going to be sent. + * @param filename The requested filename. + * @param mode The requested transfer mode. This should be on of the TFTP + * class MODE constants (e.g., TFTP.NETASCII_MODE). + ***/ + public TFTPWriteRequestPacket(InetAddress destination, int port, + String filename, int mode) + { + super(destination, port, TFTPPacket.WRITE_REQUEST, filename, mode); + } + + /*** + * Creates a write request packet of based on a received + * datagram and assumes the datagram has already been identified as a + * write request. Assumes the datagram is at least length 4, else an + * ArrayIndexOutOfBoundsException may be thrown. + *

+ * @param datagram The datagram containing the received request. + * @throws TFTPPacketException If the datagram isn't a valid TFTP + * request packet. + ***/ + TFTPWriteRequestPacket(DatagramPacket datagram) throws TFTPPacketException + { + super(TFTPPacket.WRITE_REQUEST, datagram); + } +} diff --git a/org/apache/commons/net/time/TimeTCPClient.java b/org/apache/commons/net/time/TimeTCPClient.java new file mode 100644 index 0000000..ad10ba5 --- /dev/null +++ b/org/apache/commons/net/time/TimeTCPClient.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.time; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Date; + +import org.apache.commons.net.SocketClient; + +/*** + * The TimeTCPClient class is a TCP implementation of a client for the + * Time protocol described in RFC 868. To use the class, merely + * establish a connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * and call either {@link #getTime getTime() } or + * {@link #getDate getDate() } to retrieve the time, then + * call {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * to close the connection properly. + *

+ *

+ * @author Daniel F. Savarese + * @see TimeUDPClient + ***/ + +public final class TimeTCPClient extends SocketClient +{ + /*** The default time port. It is set to 37 according to RFC 868. ***/ + public static final int DEFAULT_PORT = 37; + + /*** + * The number of seconds between 00:00 1 January 1900 and + * 00:00 1 January 1970. This value can be useful for converting + * time values to other formats. + ***/ + public static final long SECONDS_1900_TO_1970 = 2208988800L; + + /*** + * The default TimeTCPClient constructor. It merely sets the default + * port to DEFAULT_PORT . + ***/ + public TimeTCPClient () + { + setDefaultPort(DEFAULT_PORT); + } + + /*** + * Retrieves the time from the server and returns it. The time + * is the number of seconds since 00:00 (midnight) 1 January 1900 GMT, + * as specified by RFC 868. This method reads the raw 32-bit big-endian + * unsigned integer from the server, converts it to a Java long, and + * returns the value. + *

+ * The server will have closed the connection at this point, so you should + * call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * after calling this method. To retrieve another time, you must + * initiate another connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before calling getTime() again. + *

+ * @return The time value retrieved from the server. + * @exception IOException If an error occurs while fetching the time. + ***/ + public long getTime() throws IOException + { + DataInputStream input; + input = new DataInputStream(_input_); + return (input.readInt() & 0xffffffffL); + } + + /*** + * Retrieves the time from the server and returns a Java Date + * containing the time converted to the local timezone. + *

+ * The server will have closed the connection at this point, so you should + * call + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * after calling this method. To retrieve another time, you must + * initiate another connection with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before calling getDate() again. + *

+ * @return A Date value containing the time retrieved from the server + * converted to the local timezone. + * @exception IOException If an error occurs while fetching the time. + ***/ + public Date getDate() throws IOException + { + return new Date((getTime() - SECONDS_1900_TO_1970)*1000L); + } + +} + diff --git a/org/apache/commons/net/time/TimeUDPClient.java b/org/apache/commons/net/time/TimeUDPClient.java new file mode 100644 index 0000000..f58d96e --- /dev/null +++ b/org/apache/commons/net/time/TimeUDPClient.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.time; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.util.Date; + +import org.apache.commons.net.DatagramSocketClient; + +/*** + * The TimeUDPClient class is a UDP implementation of a client for the + * Time protocol described in RFC 868. To use the class, merely + * open a local datagram socket with + * {@link org.apache.commons.net.DatagramSocketClient#open open } + * and call {@link #getTime getTime } or + * {@link #getTime getDate } to retrieve the time. Then call + * {@link org.apache.commons.net.DatagramSocketClient#close close } + * to close the connection properly. Unlike + * {@link org.apache.commons.net.time.TimeTCPClient}, + * successive calls to {@link #getTime getTime } or + * {@link #getDate getDate } are permitted + * without re-establishing a connection. That is because UDP is a + * connectionless protocol and the Time protocol is stateless. + *

+ *

+ * @author Daniel F. Savarese + * @see TimeTCPClient + ***/ + +public final class TimeUDPClient extends DatagramSocketClient +{ + /*** The default time port. It is set to 37 according to RFC 868. ***/ + public static final int DEFAULT_PORT = 37; + + /*** + * The number of seconds between 00:00 1 January 1900 and + * 00:00 1 January 1970. This value can be useful for converting + * time values to other formats. + ***/ + public static final long SECONDS_1900_TO_1970 = 2208988800L; + + private byte[] __dummyData = new byte[1]; + private byte[] __timeData = new byte[4]; + + /*** + * Retrieves the time from the specified server and port and + * returns it. The time is the number of seconds since + * 00:00 (midnight) 1 January 1900 GMT, as specified by RFC 868. + * This method reads the raw 32-bit big-endian + * unsigned integer from the server, converts it to a Java long, and + * returns the value. + *

+ * @param host The address of the server. + * @param port The port of the service. + * @return The time value retrieved from the server. + * @exception IOException If an error occurs while retrieving the time. + ***/ + public long getTime(InetAddress host, int port) throws IOException + { + long time; + DatagramPacket sendPacket, receivePacket; + + sendPacket = + new DatagramPacket(__dummyData, __dummyData.length, host, port); + receivePacket = new DatagramPacket(__timeData, __timeData.length); + + _socket_.send(sendPacket); + _socket_.receive(receivePacket); + + time = 0L; + time |= (((__timeData[0] & 0xff) << 24) & 0xffffffffL); + time |= (((__timeData[1] & 0xff) << 16) & 0xffffffffL); + time |= (((__timeData[2] & 0xff) << 8) & 0xffffffffL); + time |= ((__timeData[3] & 0xff) & 0xffffffffL); + + return time; + } + + /*** Same as getTime(host, DEFAULT_PORT); ***/ + public long getTime(InetAddress host) throws IOException + { + return getTime(host, DEFAULT_PORT); + } + + + /*** + * Retrieves the time from the server and returns a Java Date + * containing the time converted to the local timezone. + *

+ * @param host The address of the server. + * @param port The port of the service. + * @return A Date value containing the time retrieved from the server + * converted to the local timezone. + * @exception IOException If an error occurs while fetching the time. + ***/ + public Date getDate(InetAddress host, int port) throws IOException + { + return new Date((getTime(host, port) - SECONDS_1900_TO_1970)*1000L); + } + + + /*** Same as getTime(host, DEFAULT_PORT); ***/ + public Date getDate(InetAddress host) throws IOException + { + return new Date((getTime(host, DEFAULT_PORT) - + SECONDS_1900_TO_1970)*1000L); + } + +} + diff --git a/org/apache/commons/net/util/ListenerList.class b/org/apache/commons/net/util/ListenerList.class new file mode 100644 index 0000000..f05ebb5 Binary files /dev/null and b/org/apache/commons/net/util/ListenerList.class differ diff --git a/org/apache/commons/net/util/ListenerList.java b/org/apache/commons/net/util/ListenerList.java new file mode 100644 index 0000000..796fb78 --- /dev/null +++ b/org/apache/commons/net/util/ListenerList.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.util; + +import java.io.Serializable; +import java.util.EventListener; +import java.util.Iterator; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author Daniel F. Savarese + */ + +public class ListenerList implements Serializable, Iterable +{ + private final CopyOnWriteArrayList __listeners; + + public ListenerList() + { + __listeners = new CopyOnWriteArrayList(); + } + + public void addListener(EventListener listener) + { + __listeners.add(listener); + } + + public void removeListener(EventListener listener) + { + __listeners.remove(listener); + } + + public int getListenerCount() + { + return __listeners.size(); + } + + /** + * Return an {@link Iterator} for the {@link EventListener} instances + * + * @since 2.0 + * TODO Check that this is a good defensive strategy + */ + public Iterator iterator() { + return __listeners.iterator(); + } + +} diff --git a/org/apache/commons/net/util/SubnetUtils.java b/org/apache/commons/net/util/SubnetUtils.java new file mode 100644 index 0000000..90cc6e8 --- /dev/null +++ b/org/apache/commons/net/util/SubnetUtils.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.net.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A class that performs some subnet calculations given a network address and a subnet mask. + * @see http://www.faqs.org/rfcs/rfc1519.html + * @author + * @since 2.0 + */ +public class SubnetUtils { + + private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"; + private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,3})"; + private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS); + private static final Pattern cidrPattern = Pattern.compile(SLASH_FORMAT); + private static final int NBITS = 32; + + private int netmask = 0; + private int address = 0; + private int network = 0; + private int broadcast = 0; + + /** + * Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" + * @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16" + */ + public SubnetUtils(String cidrNotation) { + calculate(cidrNotation); + } + + /** + * Constructor that takes two dotted decimal addresses. + * @param address An IP address, e.g. "192.168.0.1" + * @param mask A dotted decimal netmask e.g. "255.255.0.0" + */ + public SubnetUtils(String address, String mask) { + calculate(toCidrNotation(address, mask)); + } + + /** + * Convenience container for subnet summary information. + * + */ + public final class SubnetInfo { + private SubnetInfo() {} + + private int netmask() { return netmask; } + private int network() { return network; } + private int address() { return address; } + private int broadcast() { return broadcast; } + private int low() { return network() + 1; } + private int high() { return broadcast() - 1; } + + public boolean isInRange(String address) { return isInRange(toInteger(address)); } + private boolean isInRange(int address) { return ((address-low()) <= (high()-low())); } + + public String getBroadcastAddress() { return format(toArray(broadcast())); } + public String getNetworkAddress() { return format(toArray(network())); } + public String getNetmask() { return format(toArray(netmask())); } + public String getAddress() { return format(toArray(address())); } + public String getLowAddress() { return format(toArray(low())); } + public String getHighAddress() { return format(toArray(high())); } + public int getAddressCount() { return (broadcast() - low()); } + + public int asInteger(String address) { return toInteger(address); } + + public String getCidrSignature() { + return toCidrNotation( + format(toArray(address())), + format(toArray(netmask())) + ); + } + + public String[] getAllAddresses() { + String[] addresses = new String[getAddressCount()]; + for (int add = low(), j=0; add <= high(); ++add, ++j) { + addresses[j] = format(toArray(add)); + } + return addresses; + } + } + + /** + * Return a {@link SubnetInfo} instance that contains subnet-specific statistics + * @return + */ + public final SubnetInfo getInfo() { return new SubnetInfo(); } + + /* + * Initialize the internal fields from the supplied CIDR mask + */ + private void calculate(String mask) { + Matcher matcher = cidrPattern.matcher(mask); + + if (matcher.matches()) { + address = matchAddress(matcher); + + /* Create a binary netmask from the number of bits specification /x */ + int cidrPart = rangeCheck(Integer.parseInt(matcher.group(5)), 0, NBITS-1); + for (int j = 0; j < cidrPart; ++j) { + netmask |= (1 << 31-j); + } + + /* Calculate base network address */ + network = (address & netmask); + + /* Calculate broadcast address */ + broadcast = network | ~(netmask); + } + else + throw new IllegalArgumentException("Could not parse [" + mask + "]"); + } + + /* + * Convert a dotted decimal format address to a packed integer format + */ + private int toInteger(String address) { + Matcher matcher = addressPattern.matcher(address); + if (matcher.matches()) { + return matchAddress(matcher); + } + else + throw new IllegalArgumentException("Could not parse [" + address + "]"); + } + + /* + * Convenience method to extract the components of a dotted decimal address and + * pack into an integer using a regex match + */ + private int matchAddress(Matcher matcher) { + int addr = 0; + for (int i = 1; i <= 4; ++i) { + int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255)); + addr |= ((n & 0xff) << 8*(4-i)); + } + return addr; + } + + /* + * Convert a packed integer address into a 4-element array + */ + private int[] toArray(int val) { + int ret[] = new int[4]; + for (int j = 3; j >= 0; --j) + ret[j] |= ((val >>> 8*(3-j)) & (0xff)); + return ret; + } + + /* + * Convert a 4-element array into dotted decimal format + */ + private String format(int[] octets) { + StringBuilder str = new StringBuilder(); + for (int i =0; i < octets.length; ++i){ + str.append(octets[i]); + if (i != octets.length - 1) { + str.append("."); + } + } + return str.toString(); + } + + /* + * Convenience function to check integer boundaries + */ + private int rangeCheck(int value, int begin, int end) { + if (value >= begin && value <= end) + return value; + + throw new IllegalArgumentException("Value out of range: [" + value + "]"); + } + + /* + * Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy + * see Hacker's Delight section 5.1 + */ + int pop(int x) { + x = x - ((x >>> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); + x = (x + (x >>> 4)) & 0x0F0F0F0F; + x = x + (x >>> 8); + x = x + (x >>> 16); + return x & 0x0000003F; + } + + /* Convert two dotted decimal addresses to a single xxx.xxx.xxx.xxx/yy format + * by counting the 1-bit population in the mask address. (It may be better to count + * NBITS-#trailing zeroes for this case) + */ + private String toCidrNotation(String addr, String mask) { + return addr + "/" + pop(toInteger(mask)); + } +} diff --git a/org/apache/commons/net/whois/WhoisClient.java b/org/apache/commons/net/whois/WhoisClient.java new file mode 100644 index 0000000..74cc064 --- /dev/null +++ b/org/apache/commons/net/whois/WhoisClient.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.whois; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.net.finger.FingerClient; + +/*** + * The WhoisClient class implements the client side of the Internet Whois + * Protocol defined in RFC 954. To query a host you create a + * WhoisClient instance, connect to the host, query the host, and finally + * disconnect from the host. If the whois service you want to query is on + * a non-standard port, connect to the host at that port. + * Here's a sample use: + *

+ *    WhoisClient whois;
+ *
+ *    whois = new WhoisClient();
+ *
+ *    try {
+ *      whois.connect(WhoisClient.DEFAULT_HOST);
+ *      System.out.println(whois.query("foobar"));
+ *      whois.disconnect();
+ *    } catch(IOException e) {
+ *      System.err.println("Error I/O exception: " + e.getMessage());
+ *      return;
+ *    }
+ * 
+ * + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class WhoisClient extends FingerClient +{ + /*** + * The default whois host to query. It is set to whois.internic.net. + ***/ + public static final String DEFAULT_HOST = "whois.internic.net"; + + /*** + * The default whois port. It is set to 43 according to RFC 954. + ***/ + public static final int DEFAULT_PORT = 43; + + + /*** + * The default whois constructor. Initializes the + * default port to DEFAULT_PORT . + ***/ + public WhoisClient() + { + setDefaultPort(DEFAULT_PORT); + } + + /*** + * Queries the connected whois server for information regarding + * the given handle. It is up to the programmer to be familiar with the + * handle syntax of the whois server. You must first connect to a whois + * server before calling this method, and you should disconnect afterward. + *

+ * @param handle The handle to lookup. + * @return The result of the whois query. + * @exception IOException If an I/O error occurs during the operation. + ***/ + public String query(String handle) throws IOException + { + return query(false, handle); + } + + + /*** + * Queries the connected whois server for information regarding + * the given handle and returns the InputStream of the network connection. + * It is up to the programmer to be familiar with the handle syntax + * of the whois server. You must first connect to a finger server before + * calling this method, and you should disconnect after finishing reading + * the stream. + *

+ * @param handle The handle to lookup. + * @return The InputStream of the network connection of the whois query. + * Can be read to obtain whois results. + * @exception IOException If an I/O error occurs during the operation. + ***/ + public InputStream getInputStream(String handle) throws IOException + { + return getInputStream(false, handle); + } + +} + diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png new file mode 100644 index 0000000..8074c4c Binary files /dev/null and b/res/drawable-hdpi/icon.png differ diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi/icon.png new file mode 100644 index 0000000..1095584 Binary files /dev/null and b/res/drawable-ldpi/icon.png differ diff --git a/res/drawable-mdpi/icon.png b/res/drawable-mdpi/icon.png new file mode 100644 index 0000000..a07c69f Binary files /dev/null and b/res/drawable-mdpi/icon.png differ diff --git a/res/layout/filerow.xml b/res/layout/filerow.xml new file mode 100644 index 0000000..7f12ffa --- /dev/null +++ b/res/layout/filerow.xml @@ -0,0 +1,7 @@ + + + diff --git a/res/layout/main.xml b/res/layout/main.xml new file mode 100644 index 0000000..13a38b7 --- /dev/null +++ b/res/layout/main.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..4f00040 --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World, fileBrowser! + blauploader + diff --git a/src/com/lc8n/blauploader/FileBrowser.java b/src/com/lc8n/blauploader/FileBrowser.java new file mode 100644 index 0000000..6546327 --- /dev/null +++ b/src/com/lc8n/blauploader/FileBrowser.java @@ -0,0 +1,198 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + Copyright 2010 Joe Robinson +*/ + +package com.lc8n.blauploader; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +public class FileBrowser extends ListActivity { + /** Called when the activity is first created. */ + + private List directoryEntries = new ArrayList(); + private File currentDirectory = new File("/"); + private float fileSize = 0; + private Handler pbHandle = null; + private ProgressDialog progressDialog; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + + directoryEntries.clear(); + + File[] files = currentDirectory.listFiles(); + directoryEntries.add("Directory:"+currentDirectory.getAbsolutePath()); + directoryEntries.add("Up One Level"); + if (files != null) + { + for (File file: files) + { + directoryEntries.add(file.getPath()); +// System.out.println(file.getPath()); + } + } + ArrayAdapter directoryList = new ArrayAdapter(this, R.layout.filerow, this.directoryEntries); + + this.setListAdapter(directoryList); + + progressDialog = new ProgressDialog(this); + + + progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progressDialog.setMessage("Blauploading..."); + progressDialog.setCancelable(true); + progressDialog.setProgress(0); + + +// +// + + + + pbHandle = new Handler(){ + + @Override + public void handleMessage(Message msg) { + + /* get the value from the Message */ + + long progress = msg.getData().getLong("progress_update"); + System.out.println(progress+"/"+fileSize); + if(progress>(fileSize-10240)) + { + progressDialog.dismiss(); + } + float percent = (progress/fileSize)*100; + Integer intProgress = Math.round(percent); + if(intProgress==100) + { + progressDialog.dismiss(); + } + else + { + progressDialog.show(); + progressDialog.setProgress(intProgress); + } + } + }; + + } + + public void browseTo(File dir) + { + directoryEntries.clear(); + + File[] files = dir.listFiles(); + directoryEntries.add("Current Directory:"+currentDirectory.getAbsolutePath()); + directoryEntries.add("Up One Level"); + +// System.out.println(files.length); + if(files != null) + { + for (File file: files) + { + directoryEntries.add(file.getPath()); + System.out.println(file.getPath()); + } + } + ArrayAdapter directoryList = new ArrayAdapter(this, R.layout.filerow, this.directoryEntries); + + this.setListAdapter(directoryList); + } + + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + + String fileString = directoryEntries.get(position); + + + if(fileString.contains("Directory:")) + { + browseTo(currentDirectory); + } + else if (fileString.equals("Up One Level")) + { + System.out.println(currentDirectory.getParentFile().getPath()); + if (currentDirectory.getParent() != null) + { + currentDirectory = currentDirectory.getParentFile(); + browseTo(currentDirectory); + } + } + else + { + + + File chosenFile = new File(fileString); + if (chosenFile.isDirectory()) + { + currentDirectory = chosenFile; + browseTo(currentDirectory); + } + else + { + + //upload it + try { + + fileSize = chosenFile.length(); + + + + + + + FileUpload fu = new FileUpload(chosenFile,pbHandle); + Thread thread = new Thread(fu); + + thread.start(); + + + + + } catch (Exception e) { + // TODO Auto-generated catch block + System.err.println(e.getMessage()); + e.printStackTrace(); + } + + } + + } + + + + } + + + +} \ No newline at end of file diff --git a/src/com/lc8n/blauploader/FileUpload.java b/src/com/lc8n/blauploader/FileUpload.java new file mode 100644 index 0000000..b81ec2d --- /dev/null +++ b/src/com/lc8n/blauploader/FileUpload.java @@ -0,0 +1,76 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + Copyright 2010 Joe Robinson +*/ + +package com.lc8n.blauploader; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.SocketException; + +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPClient; + +import android.os.Handler; + +public class FileUpload implements Runnable{ + + private File file; + private Handler pbHandle; + public FileUpload(File file, Handler pbHandle) + { + this.file = file; + this.pbHandle = pbHandle; + } + + public void uploadFile(File file, Handler pbHandle) throws SocketException, IOException + { + + + FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + ProgressInputStream pis = new ProgressInputStream(bis,pbHandle); + String fileName = file.getName(); + FTPClient ftpClient = new FTPClient(); + + ftpClient.connect("tghost.co.uk"); + ftpClient.login("blaupload", "lemons"); + ftpClient.setFileType(FTP.BINARY_FILE_TYPE); + ftpClient.enterLocalPassiveMode(); + ftpClient.changeWorkingDirectory("/"); + ftpClient.storeFile(fileName, pis); + bis.close(); + pis.close(); + ftpClient.logout(); + ftpClient.disconnect(); + + } + public void run() { + try { + uploadFile(file, pbHandle); + } catch (Exception e) { + + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + +} diff --git a/src/com/lc8n/blauploader/ProgressInputStream.java b/src/com/lc8n/blauploader/ProgressInputStream.java new file mode 100644 index 0000000..bda5980 --- /dev/null +++ b/src/com/lc8n/blauploader/ProgressInputStream.java @@ -0,0 +1,97 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + Copyright 2010 Joe Robinson +*/ + +package com.lc8n.blauploader; + +import java.io.IOException; +import java.io.InputStream; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; + +public class ProgressInputStream extends InputStream { + + /* Key to retrieve progress value from message bundle passed to handler */ + public static final String PROGRESS_UPDATE = "progress_update"; + + private static final int TEN_KILOBYTES = 1024 * 10; + + private InputStream inputStream; + private Handler handler; + + private long progress; + private long lastUpdate; + + private boolean closed; + + public ProgressInputStream(InputStream inputStream, Handler handler) { + this.inputStream = inputStream; + this.handler = handler; + + this.progress = 0; + this.lastUpdate = 0; + + this.closed = false; + } + + @Override + public int read() throws IOException { + int count = inputStream.read(); + return incrementCounterAndUpdateDisplay(count); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int count = inputStream.read(b, off, len); + return incrementCounterAndUpdateDisplay(count); + } + + @Override + public void close() throws IOException { + super.close(); + if (closed) + throw new IOException("already closed"); + closed = true; + } + + private int incrementCounterAndUpdateDisplay(int count) { + if (count > 0) + progress += count; + lastUpdate = maybeUpdateDisplay(progress, lastUpdate); + return count; + } + + private long maybeUpdateDisplay(long progress, long lastUpdate) { + if (progress - lastUpdate > TEN_KILOBYTES) { + lastUpdate = progress; + sendLong(PROGRESS_UPDATE, progress); + } + return lastUpdate; + } + + public void sendLong(String key, long value) { + Bundle data = new Bundle(); + data.putLong(key, value); + + Message message = Message.obtain(); + message.setData(data); + handler.sendMessage(message); + } +} \ No newline at end of file diff --git a/src/org/apache/commons/net/DatagramSocketClient.java b/src/org/apache/commons/net/DatagramSocketClient.java new file mode 100644 index 0000000..9199704 --- /dev/null +++ b/src/org/apache/commons/net/DatagramSocketClient.java @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/*** + * The DatagramSocketClient provides the basic operations that are required + * of client objects accessing datagram sockets. It is meant to be + * subclassed to avoid having to rewrite the same code over and over again + * to open a socket, close a socket, set timeouts, etc. Of special note + * is the {@link #setDatagramSocketFactory setDatagramSocketFactory } + * method, which allows you to control the type of DatagramSocket the + * DatagramSocketClient creates for network communications. This is + * especially useful for adding things like proxy support as well as better + * support for applets. For + * example, you could create a + * {@link org.apache.commons.net.DatagramSocketFactory} + * that + * requests browser security capabilities before creating a socket. + * All classes derived from DatagramSocketClient should use the + * {@link #_socketFactory_ _socketFactory_ } member variable to + * create DatagramSocket instances rather than instantiating + * them by directly invoking a constructor. By honoring this contract + * you guarantee that a user will always be able to provide his own + * Socket implementations by substituting his own SocketFactory. + *

+ *

+ * @author Daniel F. Savarese + * @see DatagramSocketFactory + ***/ + +public abstract class DatagramSocketClient +{ + /*** + * The default DatagramSocketFactory shared by all DatagramSocketClient + * instances. + ***/ + private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY = + new DefaultDatagramSocketFactory(); + + /*** The timeout to use after opening a socket. ***/ + protected int _timeout_; + + /*** The datagram socket used for the connection. ***/ + protected DatagramSocket _socket_; + + /*** + * A status variable indicating if the client's socket is currently open. + ***/ + protected boolean _isOpen_; + + /*** The datagram socket's DatagramSocketFactory. ***/ + protected DatagramSocketFactory _socketFactory_; + + /*** + * Default constructor for DatagramSocketClient. Initializes + * _socket_ to null, _timeout_ to 0, and _isOpen_ to false. + ***/ + public DatagramSocketClient() + { + _socket_ = null; + _timeout_ = 0; + _isOpen_ = false; + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + } + + + /*** + * Opens a DatagramSocket on the local host at the first available port. + * Also sets the timeout on the socket to the default timeout set + * by {@link #setDefaultTimeout setDefaultTimeout() }. + *

+ * _isOpen_ is set to true after calling this method and _socket_ + * is set to the newly opened socket. + *

+ * @exception SocketException If the socket could not be opened or the + * timeout could not be set. + ***/ + public void open() throws SocketException + { + _socket_ = _socketFactory_.createDatagramSocket(); + _socket_.setSoTimeout(_timeout_); + _isOpen_ = true; + } + + + /*** + * Opens a DatagramSocket on the local host at a specified port. + * Also sets the timeout on the socket to the default timeout set + * by {@link #setDefaultTimeout setDefaultTimeout() }. + *

+ * _isOpen_ is set to true after calling this method and _socket_ + * is set to the newly opened socket. + *

+ * @param port The port to use for the socket. + * @exception SocketException If the socket could not be opened or the + * timeout could not be set. + ***/ + public void open(int port) throws SocketException + { + _socket_ = _socketFactory_.createDatagramSocket(port); + _socket_.setSoTimeout(_timeout_); + _isOpen_ = true; + } + + + /*** + * Opens a DatagramSocket at the specified address on the local host + * at a specified port. + * Also sets the timeout on the socket to the default timeout set + * by {@link #setDefaultTimeout setDefaultTimeout() }. + *

+ * _isOpen_ is set to true after calling this method and _socket_ + * is set to the newly opened socket. + *

+ * @param port The port to use for the socket. + * @param laddr The local address to use. + * @exception SocketException If the socket could not be opened or the + * timeout could not be set. + ***/ + public void open(int port, InetAddress laddr) throws SocketException + { + _socket_ = _socketFactory_.createDatagramSocket(port, laddr); + _socket_.setSoTimeout(_timeout_); + _isOpen_ = true; + } + + + + /*** + * Closes the DatagramSocket used for the connection. + * You should call this method after you've finished using the class + * instance and also before you call {@link #open open() } + * again. _isOpen_ is set to false and _socket_ is set to null. + * If you call this method when the client socket is not open, + * a NullPointerException is thrown. + ***/ + public void close() + { + _socket_.close(); + _socket_ = null; + _isOpen_ = false; + } + + + /*** + * Returns true if the client has a currently open socket. + *

+ * @return True if the client has a curerntly open socket, false otherwise. + ***/ + public boolean isOpen() + { + return _isOpen_; + } + + + /*** + * Set the default timeout in milliseconds to use when opening a socket. + * After a call to open, the timeout for the socket is set using this value. + * This method should be used prior to a call to {@link #open open()} + * and should not be confused with {@link #setSoTimeout setSoTimeout()} + * which operates on the currently open socket. _timeout_ contains + * the new timeout value. + *

+ * @param timeout The timeout in milliseconds to use for the datagram socket + * connection. + ***/ + public void setDefaultTimeout(int timeout) + { + _timeout_ = timeout; + } + + + /*** + * Returns the default timeout in milliseconds that is used when + * opening a socket. + *

+ * @return The default timeout in milliseconds that is used when + * opening a socket. + ***/ + public int getDefaultTimeout() + { + return _timeout_; + } + + + /*** + * Set the timeout in milliseconds of a currently open connection. + * Only call this method after a connection has been opened + * by {@link #open open()}. + *

+ * @param timeout The timeout in milliseconds to use for the currently + * open datagram socket connection. + ***/ + public void setSoTimeout(int timeout) throws SocketException + { + _socket_.setSoTimeout(timeout); + } + + + /*** + * Returns the timeout in milliseconds of the currently opened socket. + * If you call this method when the client socket is not open, + * a NullPointerException is thrown. + *

+ * @return The timeout in milliseconds of the currently opened socket. + ***/ + public int getSoTimeout() throws SocketException + { + return _socket_.getSoTimeout(); + } + + + /*** + * Returns the port number of the open socket on the local host used + * for the connection. If you call this method when the client socket + * is not open, a NullPointerException is thrown. + *

+ * @return The port number of the open socket on the local host used + * for the connection. + ***/ + public int getLocalPort() + { + return _socket_.getLocalPort(); + } + + + /*** + * Returns the local address to which the client's socket is bound. + * If you call this method when the client socket is not open, a + * NullPointerException is thrown. + *

+ * @return The local address to which the client's socket is bound. + ***/ + public InetAddress getLocalAddress() + { + return _socket_.getLocalAddress(); + } + + + /*** + * Sets the DatagramSocketFactory used by the DatagramSocketClient + * to open DatagramSockets. If the factory value is null, then a default + * factory is used (only do this to reset the factory after having + * previously altered it). + *

+ * @param factory The new DatagramSocketFactory the DatagramSocketClient + * should use. + ***/ + public void setDatagramSocketFactory(DatagramSocketFactory factory) + { + if (factory == null) + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + else + _socketFactory_ = factory; + } +} diff --git a/src/org/apache/commons/net/DatagramSocketFactory.java b/src/org/apache/commons/net/DatagramSocketFactory.java new file mode 100644 index 0000000..c152eb2 --- /dev/null +++ b/src/org/apache/commons/net/DatagramSocketFactory.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/*** + * The DatagramSocketFactory interface provides a means for the + * programmer to control the creation of datagram sockets and + * provide his own DatagramSocket implementations for use by all + * classes derived from + * {@link org.apache.commons.net.DatagramSocketClient} + * . + * This allows you to provide your own DatagramSocket implementations and + * to perform security checks or browser capability requests before + * creating a DatagramSocket. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public interface DatagramSocketFactory +{ + + /*** + * Creates a DatagramSocket on the local host at the first available port. + *

+ * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket() throws SocketException; + + /*** + * Creates a DatagramSocket on the local host at a specified port. + *

+ * @param port The port to use for the socket. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port) throws SocketException; + + /*** + * Creates a DatagramSocket at the specified address on the local host + * at a specified port. + *

+ * @param port The port to use for the socket. + * @param laddr The local address to use. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port, InetAddress laddr) + throws SocketException; +} diff --git a/src/org/apache/commons/net/DefaultDatagramSocketFactory.java b/src/org/apache/commons/net/DefaultDatagramSocketFactory.java new file mode 100644 index 0000000..3983fcb --- /dev/null +++ b/src/org/apache/commons/net/DefaultDatagramSocketFactory.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/*** + * DefaultDatagramSocketFactory implements the DatagramSocketFactory + * interface by simply wrapping the java.net.DatagramSocket + * constructors. It is the default DatagramSocketFactory used by + * {@link org.apache.commons.net.DatagramSocketClient} + * implementations. + *

+ *

+ * @author Daniel F. Savarese + * @see DatagramSocketFactory + * @see DatagramSocketClient + * @see DatagramSocketClient#setDatagramSocketFactory + ***/ + +public class DefaultDatagramSocketFactory implements DatagramSocketFactory +{ + + /*** + * Creates a DatagramSocket on the local host at the first available port. + *

+ * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket() throws SocketException + { + return new DatagramSocket(); + } + + /*** + * Creates a DatagramSocket on the local host at a specified port. + *

+ * @param port The port to use for the socket. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port) throws SocketException + { + return new DatagramSocket(port); + } + + /*** + * Creates a DatagramSocket at the specified address on the local host + * at a specified port. + *

+ * @param port The port to use for the socket. + * @param laddr The local address to use. + * @exception SocketException If the socket could not be created. + ***/ + public DatagramSocket createDatagramSocket(int port, InetAddress laddr) + throws SocketException + { + return new DatagramSocket(port, laddr); + } +} diff --git a/src/org/apache/commons/net/DefaultSocketFactory.java b/src/org/apache/commons/net/DefaultSocketFactory.java new file mode 100644 index 0000000..e809f84 --- /dev/null +++ b/src/org/apache/commons/net/DefaultSocketFactory.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.SocketFactory; + +/*** + * DefaultSocketFactory implements the SocketFactory interface by + * simply wrapping the java.net.Socket and java.net.ServerSocket + * constructors. It is the default SocketFactory used by + * {@link org.apache.commons.net.SocketClient} + * implementations. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketFactory + * @see SocketClient + * @see SocketClient#setSocketFactory + ***/ + +public class DefaultSocketFactory extends SocketFactory +{ + + /*** + * Creates a Socket connected to the given host and port. + *

+ * @param host The hostname to connect to. + * @param port The port to connect to. + * @return A Socket connected to the given host and port. + * @exception UnknownHostException If the hostname cannot be resolved. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(String host, int port) + throws UnknownHostException, IOException + { + return new Socket(host, port); + } + + /*** + * Creates a Socket connected to the given host and port. + *

+ * @param address The address of the host to connect to. + * @param port The port to connect to. + * @return A Socket connected to the given host and port. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(InetAddress address, int port) + throws IOException + { + return new Socket(address, port); + } + + /*** + * Creates a Socket connected to the given host and port and + * originating from the specified local address and port. + *

+ * @param host The hostname to connect to. + * @param port The port to connect to. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @return A Socket connected to the given host and port. + * @exception UnknownHostException If the hostname cannot be resolved. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(String host, int port, + InetAddress localAddr, int localPort) + throws UnknownHostException, IOException + { + return new Socket(host, port, localAddr, localPort); + } + + /*** + * Creates a Socket connected to the given host and port and + * originating from the specified local address and port. + *

+ * @param address The address of the host to connect to. + * @param port The port to connect to. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @return A Socket connected to the given host and port. + * @exception IOException If an I/O error occurs while creating the Socket. + ***/ + @Override + public Socket createSocket(InetAddress address, int port, + InetAddress localAddr, int localPort) + throws IOException + { + return new Socket(address, port, localAddr, localPort); + } + + /*** + * Creates a ServerSocket bound to a specified port. A port + * of 0 will create the ServerSocket on a system-determined free port. + *

+ * @param port The port on which to listen, or 0 to use any free port. + * @return A ServerSocket that will listen on a specified port. + * @exception IOException If an I/O error occurs while creating + * the ServerSocket. + ***/ + public ServerSocket createServerSocket(int port) throws IOException + { + return new ServerSocket(port); + } + + /*** + * Creates a ServerSocket bound to a specified port with a given + * maximum queue length for incoming connections. A port of 0 will + * create the ServerSocket on a system-determined free port. + *

+ * @param port The port on which to listen, or 0 to use any free port. + * @param backlog The maximum length of the queue for incoming connections. + * @return A ServerSocket that will listen on a specified port. + * @exception IOException If an I/O error occurs while creating + * the ServerSocket. + ***/ + public ServerSocket createServerSocket(int port, int backlog) + throws IOException + { + return new ServerSocket(port, backlog); + } + + /*** + * Creates a ServerSocket bound to a specified port on a given local + * address with a given maximum queue length for incoming connections. + * A port of 0 will + * create the ServerSocket on a system-determined free port. + *

+ * @param port The port on which to listen, or 0 to use any free port. + * @param backlog The maximum length of the queue for incoming connections. + * @param bindAddr The local address to which the ServerSocket should bind. + * @return A ServerSocket that will listen on a specified port. + * @exception IOException If an I/O error occurs while creating + * the ServerSocket. + ***/ + public ServerSocket createServerSocket(int port, int backlog, + InetAddress bindAddr) + throws IOException + { + return new ServerSocket(port, backlog, bindAddr); + } +} diff --git a/src/org/apache/commons/net/MalformedServerReplyException.java b/src/org/apache/commons/net/MalformedServerReplyException.java new file mode 100644 index 0000000..3cad5f0 --- /dev/null +++ b/src/org/apache/commons/net/MalformedServerReplyException.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.IOException; + +/*** + * This exception is used to indicate that the reply from a server + * could not be interpreted. Most of the NetComponents classes attempt + * to be as lenient as possible when receiving server replies. Many + * server implementations deviate from IETF protocol specifications, making + * it necessary to be as flexible as possible. However, there will be + * certain situations where it is not possible to continue an operation + * because the server reply could not be interpreted in a meaningful manner. + * In these cases, a MalformedServerReplyException should be thrown. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public class MalformedServerReplyException extends IOException +{ + + /*** Constructs a MalformedServerReplyException with no message ***/ + public MalformedServerReplyException() + { + super(); + } + + /*** + * Constructs a MalformedServerReplyException with a specified message. + *

+ * @param message The message explaining the reason for the exception. + ***/ + public MalformedServerReplyException(String message) + { + super(message); + } + +} diff --git a/src/org/apache/commons/net/PrintCommandListener.java b/src/org/apache/commons/net/PrintCommandListener.java new file mode 100644 index 0000000..d8e7a68 --- /dev/null +++ b/src/org/apache/commons/net/PrintCommandListener.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.PrintWriter; +import org.apache.commons.net.ProtocolCommandEvent; +import org.apache.commons.net.ProtocolCommandListener; + +/*** + * This is a support class for some of the example programs. It is + * a sample implementation of the ProtocolCommandListener interface + * which just prints out to a specified stream all command/reply traffic. + *

+ * + * @since 2.0 + ***/ + +public class PrintCommandListener implements ProtocolCommandListener +{ + private PrintWriter __writer; + + public PrintCommandListener(PrintWriter writer) + { + __writer = writer; + } + + public void protocolCommandSent(ProtocolCommandEvent event) + { + __writer.print(event.getMessage()); + __writer.flush(); + } + + public void protocolReplyReceived(ProtocolCommandEvent event) + { + __writer.print(event.getMessage()); + __writer.flush(); + } +} + diff --git a/src/org/apache/commons/net/ProtocolCommandEvent.java b/src/org/apache/commons/net/ProtocolCommandEvent.java new file mode 100644 index 0000000..8977c03 --- /dev/null +++ b/src/org/apache/commons/net/ProtocolCommandEvent.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; +import java.util.EventObject; + +/*** + * There exists a large class of IETF protocols that work by sending an + * ASCII text command and arguments to a server, and then receiving an + * ASCII text reply. For debugging and other purposes, it is extremely + * useful to log or keep track of the contents of the protocol messages. + * The ProtocolCommandEvent class coupled with the + * {@link org.apache.commons.net.ProtocolCommandListener} + * interface facilitate this process. + *

+ *

+ * @see ProtocolCommandListener + * @see ProtocolCommandSupport + * @author Daniel F. Savarese + ***/ + +public class ProtocolCommandEvent extends EventObject +{ + private int __replyCode; + private boolean __isCommand; + private String __message, __command; + + /*** + * Creates a ProtocolCommandEvent signalling a command was sent to + * the server. ProtocolCommandEvents created with this constructor + * should only be sent after a command has been sent, but before the + * reply has been received. + *

+ * @param source The source of the event. + * @param command The string representation of the command type sent, not + * including the arguments (e.g., "STAT" or "GET"). + * @param message The entire command string verbatim as sent to the server, + * including all arguments. + ***/ + public ProtocolCommandEvent(Object source, String command, String message) + { + super(source); + __replyCode = 0; + __message = message; + __isCommand = true; + __command = command; + } + + + /*** + * Creates a ProtocolCommandEvent signalling a reply to a command was + * received. ProtocolCommandEvents created with this constructor + * should only be sent after a complete command reply has been received + * fromt a server. + *

+ * @param source The source of the event. + * @param replyCode The integer code indicating the natureof the reply. + * This will be the protocol integer value for protocols + * that use integer reply codes, or the reply class constant + * corresponding to the reply for protocols like POP3 that use + * strings like OK rather than integer codes (i.e., POP3Repy.OK). + * @param message The entire reply as received from the server. + ***/ + public ProtocolCommandEvent(Object source, int replyCode, String message) + { + super(source); + __replyCode = replyCode; + __message = message; + __isCommand = false; + __command = null; + } + + /*** + * Returns the string representation of the command type sent (e.g., "STAT" + * or "GET"). If the ProtocolCommandEvent is a reply event, then null + * is returned. + *

+ * @return The string representation of the command type sent, or null + * if this is a reply event. + ***/ + public String getCommand() + { + return __command; + } + + + /*** + * Returns the reply code of the received server reply. Undefined if + * this is not a reply event. + *

+ * @return The reply code of the received server reply. Undefined if + * not a reply event. + ***/ + public int getReplyCode() + { + return __replyCode; + } + + /*** + * Returns true if the ProtocolCommandEvent was generated as a result + * of sending a command. + *

+ * @return true If the ProtocolCommandEvent was generated as a result + * of sending a command. False otherwise. + ***/ + public boolean isCommand() + { + return __isCommand; + } + + /*** + * Returns true if the ProtocolCommandEvent was generated as a result + * of receiving a reply. + *

+ * @return true If the ProtocolCommandEvent was generated as a result + * of receiving a reply. False otherwise. + ***/ + public boolean isReply() + { + return !isCommand(); + } + + /*** + * Returns the entire message sent to or received from the server. + *

+ * @return The entire message sent to or received from the server. + ***/ + public String getMessage() + { + return __message; + } +} diff --git a/src/org/apache/commons/net/ProtocolCommandListener.java b/src/org/apache/commons/net/ProtocolCommandListener.java new file mode 100644 index 0000000..8089926 --- /dev/null +++ b/src/org/apache/commons/net/ProtocolCommandListener.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; +import java.util.EventListener; + +/*** + * There exists a large class of IETF protocols that work by sending an + * ASCII text command and arguments to a server, and then receiving an + * ASCII text reply. For debugging and other purposes, it is extremely + * useful to log or keep track of the contents of the protocol messages. + * The ProtocolCommandListener interface coupled with the + * {@link ProtocolCommandEvent} class facilitate this process. + *

+ * To receive ProtocolCommandEvents, you merely implement the + * ProtocolCommandListener interface and register the class as a listener + * with a ProtocolCommandEvent source such as + * {@link org.apache.commons.net.ftp.FTPClient}. + *

+ *

+ * @see ProtocolCommandEvent + * @see ProtocolCommandSupport + * @author Daniel F. Savarese + ***/ + +public interface ProtocolCommandListener extends EventListener +{ + + /*** + * This method is invoked by a ProtocolCommandEvent source after + * sending a protocol command to a server. + *

+ * @param event The ProtocolCommandEvent fired. + ***/ + public void protocolCommandSent(ProtocolCommandEvent event); + + /*** + * This method is invoked by a ProtocolCommandEvent source after + * receiving a reply from a server. + *

+ * @param event The ProtocolCommandEvent fired. + ***/ + public void protocolReplyReceived(ProtocolCommandEvent event); + +} diff --git a/src/org/apache/commons/net/ProtocolCommandSupport.java b/src/org/apache/commons/net/ProtocolCommandSupport.java new file mode 100644 index 0000000..1a51fb6 --- /dev/null +++ b/src/org/apache/commons/net/ProtocolCommandSupport.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.Serializable; +import java.util.EventListener; + +import org.apache.commons.net.util.ListenerList; + +/*** + * ProtocolCommandSupport is a convenience class for managing a list of + * ProtocolCommandListeners and firing ProtocolCommandEvents. You can + * simply delegate ProtocolCommandEvent firing and listener + * registering/unregistering tasks to this class. + *

+ *

+ * @see ProtocolCommandEvent + * @see ProtocolCommandListener + * @author Daniel F. Savarese + ***/ + +public class ProtocolCommandSupport implements Serializable +{ + private Object __source; + private ListenerList __listeners; + + /*** + * Creates a ProtocolCommandSupport instant using the indicated source + * as the source of fired ProtocolCommandEvents. + *

+ * @param source The source to use for all generated ProtocolCommandEvents. + ***/ + public ProtocolCommandSupport(Object source) + { + __listeners = new ListenerList(); + __source = source; + } + + + /*** + * Fires a ProtocolCommandEvent signalling the sending of a command to all + * registered listeners, invoking their + * {@link org.apache.commons.net.ProtocolCommandListener#protocolCommandSent protocolCommandSent() } + * methods. + *

+ * @param command The string representation of the command type sent, not + * including the arguments (e.g., "STAT" or "GET"). + * @param message The entire command string verbatim as sent to the server, + * including all arguments. + ***/ + public void fireCommandSent(String command, String message) + { + ProtocolCommandEvent event; + + event = new ProtocolCommandEvent(__source, command, message); + + for (EventListener listener : __listeners) + { + ((ProtocolCommandListener)listener).protocolCommandSent(event); + } + } + + /*** + * Fires a ProtocolCommandEvent signalling the reception of a command reply + * to all registered listeners, invoking their + * {@link org.apache.commons.net.ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() } + * methods. + *

+ * @param replyCode The integer code indicating the natureof the reply. + * This will be the protocol integer value for protocols + * that use integer reply codes, or the reply class constant + * corresponding to the reply for protocols like POP3 that use + * strings like OK rather than integer codes (i.e., POP3Repy.OK). + * @param message The entire reply as received from the server. + ***/ + public void fireReplyReceived(int replyCode, String message) + { + ProtocolCommandEvent event; + event = new ProtocolCommandEvent(__source, replyCode, message); + + for (EventListener listener : __listeners) + { + ((ProtocolCommandListener)listener).protocolReplyReceived(event); + } + } + + /*** + * Adds a ProtocolCommandListener. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + __listeners.addListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandListener(ProtocolCommandListener listener) + { + __listeners.removeListener(listener); + } + + + /*** + * Returns the number of ProtocolCommandListeners currently registered. + *

+ * @return The number of ProtocolCommandListeners currently registered. + ***/ + public int getListenerCount() + { + return __listeners.getListenerCount(); + } + +} + diff --git a/src/org/apache/commons/net/SocketClient.java b/src/org/apache/commons/net/SocketClient.java new file mode 100644 index 0000000..a5a8ead --- /dev/null +++ b/src/org/apache/commons/net/SocketClient.java @@ -0,0 +1,586 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; + +import javax.net.ServerSocketFactory; +import javax.net.SocketFactory; + + +/** + * The SocketClient provides the basic operations that are required of + * client objects accessing sockets. It is meant to be + * subclassed to avoid having to rewrite the same code over and over again + * to open a socket, close a socket, set timeouts, etc. Of special note + * is the {@link #setSocketFactory setSocketFactory } + * method, which allows you to control the type of Socket the SocketClient + * creates for initiating network connections. This is especially useful + * for adding SSL or proxy support as well as better support for applets. For + * example, you could create a + * {@link org.apache.commons.net.SocketFactory} that + * requests browser security capabilities before creating a socket. + * All classes derived from SocketClient should use the + * {@link #_socketFactory_ _socketFactory_ } member variable to + * create Socket and ServerSocket instances rather than instanting + * them by directly invoking a constructor. By honoring this contract + * you guarantee that a user will always be able to provide his own + * Socket implementations by substituting his own SocketFactory. + * @author Daniel F. Savarese + * @see SocketFactory + */ +public abstract class SocketClient +{ + /** + * The end of line character sequence used by most IETF protocols. That + * is a carriage return followed by a newline: "\r\n" + */ + public static final String NETASCII_EOL = "\r\n"; + + /** The default SocketFactory shared by all SocketClient instances. */ + private static final SocketFactory __DEFAULT_SOCKET_FACTORY = + SocketFactory.getDefault(); + + private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = + ServerSocketFactory.getDefault(); + + /** The timeout to use after opening a socket. */ + protected int _timeout_; + + /** The socket used for the connection. */ + protected Socket _socket_; + + /** The default port the client should connect to. */ + protected int _defaultPort_; + + /** The socket's InputStream. */ + protected InputStream _input_; + + /** The socket's OutputStream. */ + protected OutputStream _output_; + + /** The socket's SocketFactory. */ + protected SocketFactory _socketFactory_; + + /** The socket's ServerSocket Factory. */ + protected ServerSocketFactory _serverSocketFactory_; + + /** The socket's connect timeout (0 = infinite timeout) */ + private static final int DEFAULT_CONNECT_TIMEOUT = 0; + protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; + + /** + * Default constructor for SocketClient. Initializes + * _socket_ to null, _timeout_ to 0, _defaultPort to 0, + * _isConnected_ to false, and _socketFactory_ to a shared instance of + * {@link org.apache.commons.net.DefaultSocketFactory}. + */ + public SocketClient() + { + _socket_ = null; + _input_ = null; + _output_ = null; + _timeout_ = 0; + _defaultPort_ = 0; + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; + } + + + /** + * Because there are so many connect() methods, the _connectAction_() + * method is provided as a means of performing some action immediately + * after establishing a connection, rather than reimplementing all + * of the connect() methods. The last action performed by every + * connect() method after opening a socket is to call this method. + *

+ * This method sets the timeout on the just opened socket to the default + * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, + * sets _input_ and _output_ to the socket's InputStream and OutputStream + * respectively, and sets _isConnected_ to true. + *

+ * Subclasses overriding this method should start by calling + * super._connectAction_() first to ensure the + * initialization of the aforementioned protected variables. + */ + protected void _connectAction_() throws IOException + { + _socket_.setSoTimeout(_timeout_); + _input_ = _socket_.getInputStream(); + _output_ = _socket_.getOutputStream(); + } + + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + */ + public void connect(InetAddress host, int port) + throws SocketException, IOException + { + _socket_ = _socketFactory_.createSocket(); + _socket_.connect(new InetSocketAddress(host, port), connectTimeout); + + _connectAction_(); + } + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + */ + public void connect(String hostname, int port) + throws SocketException, IOException + { + _socket_= _socketFactory_.createSocket(); + _socket_.connect(new InetSocketAddress(hostname, port), connectTimeout); + + _connectAction_(); + } + + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + */ + public void connect(InetAddress host, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException + { + _socket_ = _socketFactory_.createSocket(); + _socket_.bind(new InetSocketAddress(localAddr, localPort)); + _socket_.connect(new InetSocketAddress(host, port), connectTimeout); + + _connectAction_(); + } + + + /** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + */ + public void connect(String hostname, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException + { + _socket_ = + _socketFactory_.createSocket(hostname, port, localAddr, localPort); + _connectAction_(); + } + + + /** + * Opens a Socket connected to a remote host at the current default port + * and originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + */ + public void connect(InetAddress host) throws SocketException, IOException + { + connect(host, _defaultPort_); + } + + + /** + * Opens a Socket connected to a remote host at the current default + * port and originating from the current host at a system assigned port. + * Before returning, {@link #_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + */ + public void connect(String hostname) throws SocketException, IOException + { + connect(hostname, _defaultPort_); + } + + + /** + * Disconnects the socket connection. + * You should call this method after you've finished using the class + * instance and also before you call + * {@link #connect connect() } + * again. _isConnected_ is set to false, _socket_ is set to null, + * _input_ is set to null, and _output_ is set to null. + *

+ * @exception IOException If there is an error closing the socket. + */ + public void disconnect() throws IOException + { + if (_socket_ != null) _socket_.close(); + if (_input_ != null) _input_.close(); + if (_output_ != null) _output_.close(); + if (_socket_ != null) _socket_ = null; + _input_ = null; + _output_ = null; + } + + + /** + * Returns true if the client is currently connected to a server. + *

+ * @return True if the client is currently connected to a server, + * false otherwise. + */ + public boolean isConnected() + { + if (_socket_ == null) + return false; + + return _socket_.isConnected(); + } + + + /** + * Sets the default port the SocketClient should connect to when a port + * is not specified. The {@link #_defaultPort_ _defaultPort_ } + * variable stores this value. If never set, the default port is equal + * to zero. + *

+ * @param port The default port to set. + */ + public void setDefaultPort(int port) + { + _defaultPort_ = port; + } + + /** + * Returns the current value of the default port (stored in + * {@link #_defaultPort_ _defaultPort_ }). + *

+ * @return The current value of the default port. + */ + public int getDefaultPort() + { + return _defaultPort_; + } + + + /** + * Set the default timeout in milliseconds to use when opening a socket. + * This value is only used previous to a call to + * {@link #connect connect()} + * and should not be confused with {@link #setSoTimeout setSoTimeout()} + * which operates on an the currently opened socket. _timeout_ contains + * the new timeout value. + *

+ * @param timeout The timeout in milliseconds to use for the socket + * connection. + */ + public void setDefaultTimeout(int timeout) + { + _timeout_ = timeout; + } + + + /** + * Returns the default timeout in milliseconds that is used when + * opening a socket. + *

+ * @return The default timeout in milliseconds that is used when + * opening a socket. + */ + public int getDefaultTimeout() + { + return _timeout_; + } + + + /** + * Set the timeout in milliseconds of a currently open connection. + * Only call this method after a connection has been opened + * by {@link #connect connect()}. + *

+ * @param timeout The timeout in milliseconds to use for the currently + * open socket connection. + * @exception SocketException If the operation fails. + */ + public void setSoTimeout(int timeout) throws SocketException + { + _socket_.setSoTimeout(timeout); + } + + + /** + * Set the underlying socket send buffer size. + *

+ * @param size The size of the buffer in bytes. + * @throws SocketException + * @since 2.0 + */ + public void setSendBufferSize(int size) throws SocketException { + _socket_.setSendBufferSize(size); + } + + + /** + * Sets the underlying socket receive buffer size. + *

+ * @param size The size of the buffer in bytes. + * @throws SocketException + * @since 2.0 + */ + public void setReceiveBufferSize(int size) throws SocketException { + _socket_.setReceiveBufferSize(size); + } + + + /** + * Returns the timeout in milliseconds of the currently opened socket. + *

+ * @return The timeout in milliseconds of the currently opened socket. + * @exception SocketException If the operation fails. + */ + public int getSoTimeout() throws SocketException + { + return _socket_.getSoTimeout(); + } + + /** + * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the + * currently opened socket. + *

+ * @param on True if Nagle's algorithm is to be enabled, false if not. + * @exception SocketException If the operation fails. + */ + public void setTcpNoDelay(boolean on) throws SocketException + { + _socket_.setTcpNoDelay(on); + } + + + /** + * Returns true if Nagle's algorithm is enabled on the currently opened + * socket. + *

+ * @return True if Nagle's algorithm is enabled on the currently opened + * socket, false otherwise. + * @exception SocketException If the operation fails. + */ + public boolean getTcpNoDelay() throws SocketException + { + return _socket_.getTcpNoDelay(); + } + + + /** + * Sets the SO_LINGER timeout on the currently opened socket. + *

+ * @param on True if linger is to be enabled, false if not. + * @param val The linger timeout (in hundredths of a second?) + * @exception SocketException If the operation fails. + */ + public void setSoLinger(boolean on, int val) throws SocketException + { + _socket_.setSoLinger(on, val); + } + + + /** + * Returns the current SO_LINGER timeout of the currently opened socket. + *

+ * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns + * -1. + * @exception SocketException If the operation fails. + */ + public int getSoLinger() throws SocketException + { + return _socket_.getSoLinger(); + } + + + /** + * Returns the port number of the open socket on the local host used + * for the connection. + *

+ * @return The port number of the open socket on the local host used + * for the connection. + */ + public int getLocalPort() + { + return _socket_.getLocalPort(); + } + + + /** + * Returns the local address to which the client's socket is bound. + *

+ * @return The local address to which the client's socket is bound. + */ + public InetAddress getLocalAddress() + { + return _socket_.getLocalAddress(); + } + + /** + * Returns the port number of the remote host to which the client is + * connected. + *

+ * @return The port number of the remote host to which the client is + * connected. + */ + public int getRemotePort() + { + return _socket_.getPort(); + } + + + /** + * @return The remote address to which the client is connected. + */ + public InetAddress getRemoteAddress() + { + return _socket_.getInetAddress(); + } + + + /** + * Verifies that the remote end of the given socket is connected to the + * the same host that the SocketClient is currently connected to. This + * is useful for doing a quick security check when a client needs to + * accept a connection from a server, such as an FTP data connection or + * a BSD R command standard error stream. + *

+ * @return True if the remote hosts are the same, false if not. + */ + public boolean verifyRemote(Socket socket) + { + InetAddress host1, host2; + + host1 = socket.getInetAddress(); + host2 = getRemoteAddress(); + + return host1.equals(host2); + } + + + /** + * Sets the SocketFactory used by the SocketClient to open socket + * connections. If the factory value is null, then a default + * factory is used (only do this to reset the factory after having + * previously altered it). + *

+ * @param factory The new SocketFactory the SocketClient should use. + */ + public void setSocketFactory(SocketFactory factory) + { + if (factory == null) + _socketFactory_ = __DEFAULT_SOCKET_FACTORY; + else + _socketFactory_ = factory; + } + + /** + * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket + * connections. If the factory value is null, then a default + * factory is used (only do this to reset the factory after having + * previously altered it). + *

+ * @param factory The new ServerSocketFactory the SocketClient should use. + * @since 2.0 + */ + public void setServerSocketFactory(ServerSocketFactory factory) { + if (factory == null) + _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; + else + _serverSocketFactory_ = factory; + } + + /** + * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's + * connect() method. + * @param connectTimeout The connection timeout to use (in ms) + * @since 2.0 + */ + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + /** + * Get the underlying socket connection timeout. + * @return + * @since 2.0 + */ + public int getConnectTimeout() { + return connectTimeout; + } + + + +} + + diff --git a/src/org/apache/commons/net/ftp/Configurable.java b/src/org/apache/commons/net/ftp/Configurable.java new file mode 100644 index 0000000..5e8e749 --- /dev/null +++ b/src/org/apache/commons/net/ftp/Configurable.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + + +/** + * This interface adds the aspect of configurability by means of + * a supplied FTPClientConfig object to other classes in the + * system, especially listing parsers. + */ +public interface Configurable { + + /** + * @param config the object containing the configuration data + * @throws IllegalArgumentException if the elements of the + * config are somehow inadequate to configure the + * Configurable object. + */ + public void configure(FTPClientConfig config); +} diff --git a/src/org/apache/commons/net/ftp/FTP.java b/src/org/apache/commons/net/ftp/FTP.java new file mode 100644 index 0000000..6e2eff8 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTP.java @@ -0,0 +1,1513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Arrays; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ProtocolCommandListener; +import org.apache.commons.net.ProtocolCommandSupport; +import org.apache.commons.net.SocketClient; + +/*** + * FTP provides the basic the functionality necessary to implement your + * own FTP client. It extends org.apache.commons.net.SocketClient since + * extending TelnetClient was causing unwanted behavior (like connections + * that did not time out properly). + *

+ * To derive the full benefits of the FTP class requires some knowledge + * of the FTP protocol defined in RFC 959. However, there is no reason + * why you should have to use the FTP class. The + * {@link org.apache.commons.net.ftp.FTPClient} class, + * derived from FTP, + * implements all the functionality required of an FTP client. The + * FTP class is made public to provide access to various FTP constants + * and to make it easier for adventurous programmers (or those with + * special needs) to interact with the FTP protocol and implement their + * own clients. A set of methods with names corresponding to the FTP + * command names are provided to facilitate this interaction. + *

+ * You should keep in mind that the FTP server may choose to prematurely + * close a connection if the client has been idle for longer than a + * given time period (usually 900 seconds). The FTP class will detect a + * premature FTP server connection closing when it receives a + * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } + * response to a command. + * When that occurs, the FTP class method encountering that reply will throw + * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * . FTPConectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * , you must disconnect the connection with + * {@link #disconnect disconnect() } to properly clean up the + * system resources used by FTP. Before disconnecting, you may check the + * last reply code and text with + * {@link #getReplyCode getReplyCode }, + * {@link #getReplyString getReplyString }, + * and {@link #getReplyStrings getReplyStrings}. + * You may avoid server disconnections while the client is idle by + * periodicaly sending NOOP commands to the server. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @author Joseph Hindsley + * @see FTPClient + * @see FTPConnectionClosedException + * @see org.apache.commons.net.MalformedServerReplyException + * @version $Id: FTP.java 658520 2008-05-21 01:14:11Z sebb $ + ***/ + +public class FTP extends SocketClient +{ + /*** The default FTP data port (20). ***/ + public static final int DEFAULT_DATA_PORT = 20; + /*** The default FTP control port (21). ***/ + public static final int DEFAULT_PORT = 21; + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as ASCII. This is the default file type. All constants + * ending in FILE_TYPE are used to indicate file types. + ***/ + public static final int ASCII_FILE_TYPE = 0; + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as EBCDIC. Note however that there are several different + * EBCDIC formats. All constants ending in FILE_TYPE + * are used to indicate file types. + ***/ + public static final int EBCDIC_FILE_TYPE = 1; + + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as a binary image, i.e., no translations should be + * performed. All constants ending in FILE_TYPE are used to + * indicate file types. + ***/ + public static final int BINARY_FILE_TYPE = 2; + + /*** + * A constant used to indicate the file(s) being transfered should + * be treated as a local type. All constants ending in + * FILE_TYPE are used to indicate file types. + ***/ + public static final int LOCAL_FILE_TYPE = 3; + + /*** + * A constant used for text files to indicate a non-print text format. + * This is the default format. + * All constants ending in TEXT_FORMAT are used to indicate + * text formatting for text transfers (both ASCII and EBCDIC). + ***/ + public static final int NON_PRINT_TEXT_FORMAT = 4; + + /*** + * A constant used to indicate a text file contains format vertical format + * control characters. + * All constants ending in TEXT_FORMAT are used to indicate + * text formatting for text transfers (both ASCII and EBCDIC). + ***/ + public static final int TELNET_TEXT_FORMAT = 5; + + /*** + * A constant used to indicate a text file contains ASA vertical format + * control characters. + * All constants ending in TEXT_FORMAT are used to indicate + * text formatting for text transfers (both ASCII and EBCDIC). + ***/ + public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6; + + /*** + * A constant used to indicate a file is to be treated as a continuous + * sequence of bytes. This is the default structure. All constants ending + * in _STRUCTURE are used to indicate file structure for + * file transfers. + ***/ + public static final int FILE_STRUCTURE = 7; + + /*** + * A constant used to indicate a file is to be treated as a sequence + * of records. All constants ending in _STRUCTURE + * are used to indicate file structure for file transfers. + ***/ + public static final int RECORD_STRUCTURE = 8; + + /*** + * A constant used to indicate a file is to be treated as a set of + * independent indexed pages. All constants ending in + * _STRUCTURE are used to indicate file structure for file + * transfers. + ***/ + public static final int PAGE_STRUCTURE = 9; + + /*** + * A constant used to indicate a file is to be transfered as a stream + * of bytes. This is the default transfer mode. All constants ending + * in TRANSFER_MODE are used to indicate file transfer + * modes. + ***/ + public static final int STREAM_TRANSFER_MODE = 10; + + /*** + * A constant used to indicate a file is to be transfered as a series + * of blocks. All constants ending in TRANSFER_MODE are used + * to indicate file transfer modes. + ***/ + public static final int BLOCK_TRANSFER_MODE = 11; + + /*** + * A constant used to indicate a file is to be transfered as FTP + * compressed data. All constants ending in TRANSFER_MODE + * are used to indicate file transfer modes. + ***/ + public static final int COMPRESSED_TRANSFER_MODE = 12; + + // We have to ensure that the protocol communication is in ASCII + // but we use ISO-8859-1 just in case 8-bit characters cross + // the wire. + /** + * The default character encoding used for communicating over an + * FTP control connection. The default encoding is an + * ASCII-compatible encoding. Some FTP servers expect other + * encodings. You can change the encoding used by an FTP instance + * with {@link #setControlEncoding setControlEncoding}. + */ + public static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1"; + private static final String __modes = "AEILNTCFRPSBC"; + + private StringBuilder __commandBuffer = new StringBuilder(); + + protected int _replyCode; + protected ArrayList _replyLines; + protected boolean _newReplyString; + protected String _replyString; + protected String _controlEncoding; + + /** + * This is used to signal whether a block of multiline responses beginning + * with xxx must be terminated by the same numeric code xxx + * See section 4.2 of RFX 959 for details. + */ + protected boolean strictMultilineParsing = false; + + /** + * Wraps SocketClient._input_ to facilitate the writing of text + * to the FTP control connection. Do not access the control + * connection via SocketClient._input_. This member starts + * with a null value, is initialized in {@link #_connectAction_}, + * and set to null in {@link #disconnect}. + */ + protected BufferedReader _controlInput_; + + /** + * Wraps SocketClient._output_ to facilitate the reading of text + * from the FTP control connection. Do not access the control + * connection via SocketClient._output_. This member starts + * with a null value, is initialized in {@link #_connectAction_}, + * and set to null in {@link #disconnect}. + */ + protected BufferedWriter _controlOutput_; + + /*** + * A ProtocolCommandSupport object used to manage the registering of + * ProtocolCommandListeners and te firing of ProtocolCommandEvents. + ***/ + protected ProtocolCommandSupport _commandSupport_; + + /*** + * The default FTP constructor. Sets the default port to + * DEFAULT_PORT and initializes internal data structures + * for saving FTP reply information. + ***/ + public FTP() + { + super(); + setDefaultPort(DEFAULT_PORT); + _replyLines = new ArrayList(); + _newReplyString = false; + _replyString = null; + _commandSupport_ = new ProtocolCommandSupport(this); + _controlEncoding = DEFAULT_CONTROL_ENCODING; + } + + // The RFC-compliant multiline termination check + private boolean __strictCheck(String line, String code) { + return (!(line.startsWith(code) && line.charAt(3) == ' ')); + } + + // The strict check is too strong a condition because of non-conforming ftp + // servers like ftp.funet.fi which sent 226 as the last line of a + // 426 multi-line reply in response to ls /. We relax the condition to + // test that the line starts with a digit rather than starting with + // the code. + private boolean __lenientCheck(String line) { + return (!(line.length() >= 4 && line.charAt(3) != '-' && + Character.isDigit(line.charAt(0)))); + } + + private void __getReply() throws IOException + { + int length; + + _newReplyString = true; + _replyLines.clear(); + + String line = _controlInput_.readLine(); + + if (line == null) + throw new FTPConnectionClosedException( + "Connection closed without indication."); + + // In case we run into an anomaly we don't want fatal index exceptions + // to be thrown. + length = line.length(); + if (length < 3) + throw new MalformedServerReplyException( + "Truncated server reply: " + line); + + String code = null; + try + { + code = line.substring(0, 3); + _replyCode = Integer.parseInt(code); + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse response code.\nServer Reply: " + line); + } + + _replyLines.add(line); + + // Get extra lines if message continues. + if (length > 3 && line.charAt(3) == '-') + { + do + { + line = _controlInput_.readLine(); + + if (line == null) + throw new FTPConnectionClosedException( + "Connection closed without indication."); + + _replyLines.add(line); + + // The length() check handles problems that could arise from readLine() + // returning too soon after encountering a naked CR or some other + // anomaly. + } + while ( isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line)); + } + + if (_commandSupport_.getListenerCount() > 0) { + _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); + } + + if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { + throw new FTPConnectionClosedException("FTP response 421 received. Server closed connection."); + } + } + + /** + * Initiates control connections and gets initial reply. + * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. + */ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + _controlInput_ = + new BufferedReader(new InputStreamReader(_socket_.getInputStream(), + getControlEncoding())); + _controlOutput_ = + new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), + getControlEncoding())); + __getReply(); + // If we received code 120, we have to fetch completion reply. + if (FTPReply.isPositivePreliminary(_replyCode)) + __getReply(); + } + + + /** + * Sets the character encoding used by the FTP control connection. + * Some FTP servers require that commands be issued in a non-ASCII + * encoding like UTF-8 so that filenames with multi-byte character + * representations (e.g, Big 8) can be specified. + * + * @param encoding The new character encoding for the control connection. + */ + public void setControlEncoding(String encoding) { + _controlEncoding = encoding; + } + + + /** + * @return The character encoding used to communicate over the + * control connection. + */ + public String getControlEncoding() { + return _controlEncoding; + } + + + /*** + * Adds a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to add. + ***/ + public void addProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.addProtocolCommandListener(listener); + } + + /*** + * Removes a ProtocolCommandListener. Delegates this task to + * {@link #_commandSupport_ _commandSupport_ }. + *

+ * @param listener The ProtocolCommandListener to remove. + ***/ + public void removeProtocolCommandListener(ProtocolCommandListener listener) + { + _commandSupport_.removeProtocolCommandListener(listener); + } + + + /*** + * Closes the control connection to the FTP server and sets to null + * some internal data so that the memory may be reclaimed by the + * garbage collector. The reply text and code information from the + * last command is voided so that the memory it used may be reclaimed. + * Also sets {@link #_controlInput_} and {@link #_controlOutput_} to null. + *

+ * @exception IOException If an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + _controlInput_ = null; + _controlOutput_ = null; + _newReplyString = false; + _replyString = null; + } + + + /*** + * Sends an FTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The text representation of the FTP command to send. + * @param args The arguments to the FTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command, String args) throws IOException + { + String message; + + __commandBuffer.setLength(0); + __commandBuffer.append(command); + + if (args != null) + { + __commandBuffer.append(' '); + __commandBuffer.append(args); + } + __commandBuffer.append(SocketClient.NETASCII_EOL); + + try{ + _controlOutput_.write(message = __commandBuffer.toString()); + _controlOutput_.flush(); + } + catch (SocketException e) + { + if (!isConnected() || !socketIsConnected(_socket_)) + { + throw new FTPConnectionClosedException("Connection unexpectedly closed."); + } + else + { + throw e; + } + } + + + if (_commandSupport_.getListenerCount() > 0) + _commandSupport_.fireCommandSent(command, message); + + __getReply(); + return _replyCode; + } + + /** + * Checks if the socket is connected + * + * @param socket + * @return true if connected + */ + private boolean socketIsConnected(Socket socket) + { + if (socket == null) + { + return false; + } + + return socket.isConnected(); + + } + + /*** + * Sends an FTP command to the server, waits for a reply and returns the + * numerical response code. After invocation, for more detailed + * information, the actual reply text can be accessed by calling + * {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The FTPCommand constant corresponding to the FTP command + * to send. + * @param args The arguments to the FTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command, String args) throws IOException + { + return sendCommand(FTPCommand._commands[command], args); + } + + + /*** + * Sends an FTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The text representation of the FTP command to send. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(String command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Sends an FTP command with no arguments to the server, waits for a + * reply and returns the numerical response code. After invocation, for + * more detailed information, the actual reply text can be accessed by + * calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. + *

+ * @param command The FTPCommand constant corresponding to the FTP command + * to send. + * @return The integer value of the FTP reply code returned by the server + * in response to the command. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int sendCommand(int command) throws IOException + { + return sendCommand(command, null); + } + + + /*** + * Returns the integer value of the reply code of the last FTP reply. + * You will usually only use this method after you connect to the + * FTP server to check that the connection was successful since + * connect is of type void. + *

+ * @return The integer value of the reply code of the last FTP reply. + ***/ + public int getReplyCode() + { + return _replyCode; + } + + /*** + * Fetches a reply from the FTP server and returns the integer reply + * code. After calling this method, the actual reply text can be accessed + * from either calling {@link #getReplyString getReplyString } or + * {@link #getReplyStrings getReplyStrings }. Only use this + * method if you are implementing your own FTP client or if you need to + * fetch a secondary response from the FTP server. + *

+ * @return The integer value of the reply code of the fetched FTP reply. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while receiving the + * server reply. + ***/ + public int getReply() throws IOException + { + __getReply(); + return _replyCode; + } + + + /*** + * Returns the lines of text from the last FTP server response as an array + * of strings, one entry per line. The end of line markers of each are + * stripped from each line. + *

+ * @return The lines of text from the last FTP response as an array. + ***/ + public String[] getReplyStrings() + { + String[] lines; + lines = new String[_replyLines.size()]; + _replyLines.addAll(Arrays.asList(lines)); + return lines; + } + + /*** + * Returns the entire text of the last FTP server response exactly + * as it was received, including all end of line markers in NETASCII + * format. + *

+ * @return The entire text from the last FTP response as a String. + ***/ + public String getReplyString() + { + StringBuilder buffer; + + if (!_newReplyString) { + return _replyString; + } + + buffer = new StringBuilder(256); + + for (String line : _replyLines) { + buffer.append(line); + buffer.append(SocketClient.NETASCII_EOL); + } + + _newReplyString = false; + + return (_replyString = buffer.toString()); + } + + + /*** + * A convenience method to send the FTP USER command to the server, + * receive the reply, and return the reply code. + *

+ * @param username The username to login under. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int user(String username) throws IOException + { + return sendCommand(FTPCommand.USER, username); + } + + /** + * A convenience method to send the FTP PASS command to the server, + * receive the reply, and return the reply code. + * @param password The plain text password of the username being logged into. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int pass(String password) throws IOException + { + return sendCommand(FTPCommand.PASS, password); + } + + /*** + * A convenience method to send the FTP ACCT command to the server, + * receive the reply, and return the reply code. + *

+ * @param account The account name to access. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int acct(String account) throws IOException + { + return sendCommand(FTPCommand.ACCT, account); + } + + + /*** + * A convenience method to send the FTP ABOR command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int abor() throws IOException + { + return sendCommand(FTPCommand.ABOR); + } + + /*** + * A convenience method to send the FTP CWD command to the server, + * receive the reply, and return the reply code. + *

+ * @param directory The new working directory. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int cwd(String directory) throws IOException + { + return sendCommand(FTPCommand.CWD, directory); + } + + /*** + * A convenience method to send the FTP CDUP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int cdup() throws IOException + { + return sendCommand(FTPCommand.CDUP); + } + + /*** + * A convenience method to send the FTP QUIT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int quit() throws IOException + { + return sendCommand(FTPCommand.QUIT); + } + + /*** + * A convenience method to send the FTP REIN command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rein() throws IOException + { + return sendCommand(FTPCommand.REIN); + } + + /*** + * A convenience method to send the FTP SMNT command to the server, + * receive the reply, and return the reply code. + *

+ * @param dir The directory name. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int smnt(String dir) throws IOException + { + return sendCommand(FTPCommand.SMNT, dir); + } + + /*** + * A convenience method to send the FTP PORT command to the server, + * receive the reply, and return the reply code. + *

+ * @param host The host owning the port. + * @param port The new port. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int port(InetAddress host, int port) throws IOException + { + int num; + StringBuffer info = new StringBuffer(24); + + info.append(host.getHostAddress().replace('.', ',')); + num = port >>> 8; + info.append(','); + info.append(num); + info.append(','); + num = port & 0xff; + info.append(num); + + return sendCommand(FTPCommand.PORT, info.toString()); + } + + /*** + * A convenience method to send the FTP PASV command to the server, + * receive the reply, and return the reply code. Remember, it's up + * to you to interpret the reply string containing the host/port + * information. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int pasv() throws IOException + { + return sendCommand(FTPCommand.PASV); + } + + /** + * A convenience method to send the FTP TYPE command for text files + * to the server, receive the reply, and return the reply code. + * @param fileType The type of the file (one of the FILE_TYPE + * constants). + * @param formatOrByteSize The format of the file (one of the + * _FORMAT constants. In the case of + * LOCAL_FILE_TYPE, the byte size. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int type(int fileType, int formatOrByteSize) throws IOException + { + StringBuffer arg = new StringBuffer(); + + arg.append(__modes.charAt(fileType)); + arg.append(' '); + if (fileType == LOCAL_FILE_TYPE) + arg.append(formatOrByteSize); + else + arg.append(__modes.charAt(formatOrByteSize)); + + return sendCommand(FTPCommand.TYPE, arg.toString()); + } + + + /** + * A convenience method to send the FTP TYPE command to the server, + * receive the reply, and return the reply code. + *

+ * @param fileType The type of the file (one of the FILE_TYPE + * constants). + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int type(int fileType) throws IOException + { + return sendCommand(FTPCommand.TYPE, + __modes.substring(fileType, fileType + 1)); + } + + /*** + * A convenience method to send the FTP STRU command to the server, + * receive the reply, and return the reply code. + *

+ * @param structure The structure of the file (one of the + * _STRUCTURE constants). + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stru(int structure) throws IOException + { + return sendCommand(FTPCommand.STRU, + __modes.substring(structure, structure + 1)); + } + + /*** + * A convenience method to send the FTP MODE command to the server, + * receive the reply, and return the reply code. + *

+ * @param mode The transfer mode to use (one of the + * TRANSFER_MODE constants). + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int mode(int mode) throws IOException + { + return sendCommand(FTPCommand.MODE, + __modes.substring(mode, mode + 1)); + } + + /*** + * A convenience method to send the FTP RETR command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname of the file to retrieve. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int retr(String pathname) throws IOException + { + return sendCommand(FTPCommand.RETR, pathname); + } + + /*** + * A convenience method to send the FTP STOR command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to use for the file when stored at + * the remote end of the transfer. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stor(String pathname) throws IOException + { + return sendCommand(FTPCommand.STOR, pathname); + } + + /*** + * A convenience method to send the FTP STOU command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stou() throws IOException + { + return sendCommand(FTPCommand.STOU); + } + + /*** + * A convenience method to send the FTP STOU command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + * @param pathname The base pathname to use for the file when stored at + * the remote end of the transfer. Some FTP servers + * require this. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + */ + public int stou(String pathname) throws IOException + { + return sendCommand(FTPCommand.STOU, pathname); + } + + /*** + * A convenience method to send the FTP APPE command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to use for the file when stored at + * the remote end of the transfer. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int appe(String pathname) throws IOException + { + return sendCommand(FTPCommand.APPE, pathname); + } + + /*** + * A convenience method to send the FTP ALLO command to the server, + * receive the reply, and return the reply code. + *

+ * @param bytes The number of bytes to allocate. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int allo(int bytes) throws IOException + { + return sendCommand(FTPCommand.ALLO, Integer.toString(bytes)); + } + + /*** + * A convenience method to send the FTP ALLO command to the server, + * receive the reply, and return the reply code. + *

+ * @param bytes The number of bytes to allocate. + * @param recordSize The size of a record. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int allo(int bytes, int recordSize) throws IOException + { + return sendCommand(FTPCommand.ALLO, Integer.toString(bytes) + " R " + + Integer.toString(recordSize)); + } + + /*** + * A convenience method to send the FTP REST command to the server, + * receive the reply, and return the reply code. + *

+ * @param marker The marker at which to restart a transfer. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rest(String marker) throws IOException + { + return sendCommand(FTPCommand.REST, marker); + } + + + /** + * @since 2.0 + **/ + public int mdtm(String file) throws IOException + { + return sendCommand(FTPCommand.MDTM, file); + } + + /*** + * A convenience method to send the FTP RNFR command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname to rename from. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rnfr(String pathname) throws IOException + { + return sendCommand(FTPCommand.RNFR, pathname); + } + + /*** + * A convenience method to send the FTP RNTO command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname to rename to + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rnto(String pathname) throws IOException + { + return sendCommand(FTPCommand.RNTO, pathname); + } + + /*** + * A convenience method to send the FTP DELE command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname to delete. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int dele(String pathname) throws IOException + { + return sendCommand(FTPCommand.DELE, pathname); + } + + /*** + * A convenience method to send the FTP RMD command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname of the directory to remove. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int rmd(String pathname) throws IOException + { + return sendCommand(FTPCommand.RMD, pathname); + } + + /*** + * A convenience method to send the FTP MKD command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname The pathname of the new directory to create. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int mkd(String pathname) throws IOException + { + return sendCommand(FTPCommand.MKD, pathname); + } + + /*** + * A convenience method to send the FTP PWD command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int pwd() throws IOException + { + return sendCommand(FTPCommand.PWD); + } + + /*** + * A convenience method to send the FTP LIST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int list() throws IOException + { + return sendCommand(FTPCommand.LIST); + } + + /*** + * A convenience method to send the FTP LIST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to list. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int list(String pathname) throws IOException + { + return sendCommand(FTPCommand.LIST, pathname); + } + + /*** + * A convenience method to send the FTP NLST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int nlst() throws IOException + { + return sendCommand(FTPCommand.NLST); + } + + /*** + * A convenience method to send the FTP NLST command to the server, + * receive the reply, and return the reply code. Remember, it is up + * to you to manage the data connection. If you don't need this low + * level of access, use {@link org.apache.commons.net.ftp.FTPClient} + * , which will handle all low level details for you. + *

+ * @param pathname The pathname to list. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int nlst(String pathname) throws IOException + { + return sendCommand(FTPCommand.NLST, pathname); + } + + /*** + * A convenience method to send the FTP SITE command to the server, + * receive the reply, and return the reply code. + *

+ * @param parameters The site parameters to send. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int site(String parameters) throws IOException + { + return sendCommand(FTPCommand.SITE, parameters); + } + + /*** + * A convenience method to send the FTP SYST command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int syst() throws IOException + { + return sendCommand(FTPCommand.SYST); + } + + /*** + * A convenience method to send the FTP STAT command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat() throws IOException + { + return sendCommand(FTPCommand.STAT); + } + + /*** + * A convenience method to send the FTP STAT command to the server, + * receive the reply, and return the reply code. + *

+ * @param pathname A pathname to list. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int stat(String pathname) throws IOException + { + return sendCommand(FTPCommand.STAT, pathname); + } + + /*** + * A convenience method to send the FTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help() throws IOException + { + return sendCommand(FTPCommand.HELP); + } + + /*** + * A convenience method to send the FTP HELP command to the server, + * receive the reply, and return the reply code. + *

+ * @param command The command name on which to request help. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int help(String command) throws IOException + { + return sendCommand(FTPCommand.HELP, command); + } + + /*** + * A convenience method to send the FTP NOOP command to the server, + * receive the reply, and return the reply code. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int noop() throws IOException + { + return sendCommand(FTPCommand.NOOP); + } + + /** + * Return whether strict multiline parsing is enabled, as per RFX 959, section 4.2. + * @return True if strict, false if lenient + * @since 2.0 + */ + public boolean isStrictMultilineParsing() { + return strictMultilineParsing; + } + + /** + * Set strict multiline parsing. + * @param strictMultilineParsing + * @since 2.0 + */ + public void setStrictMultilineParsing(boolean strictMultilineParsing) { + this.strictMultilineParsing = strictMultilineParsing; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/src/org/apache/commons/net/ftp/FTPClient.java b/src/org/apache/commons/net/ftp/FTPClient.java new file mode 100644 index 0000000..9a2c459 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPClient.java @@ -0,0 +1,2447 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; + +import org.apache.commons.net.MalformedServerReplyException; +import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory; +import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory; +import org.apache.commons.net.ftp.parser.ParserInitializationException; +import org.apache.commons.net.io.CopyStreamEvent; +import org.apache.commons.net.io.CopyStreamException; +import org.apache.commons.net.io.FromNetASCIIInputStream; +import org.apache.commons.net.io.ToNetASCIIOutputStream; +import org.apache.commons.net.io.Util; + +/*** + * FTPClient encapsulates all the functionality necessary to store and + * retrieve files from an FTP server. This class takes care of all + * low level details of interacting with an FTP server and provides + * a convenient higher level interface. As with all classes derived + * from {@link org.apache.commons.net.SocketClient}, + * you must first connect to the server with + * {@link org.apache.commons.net.SocketClient#connect connect } + * before doing anything, and finally + * {@link org.apache.commons.net.SocketClient#disconnect disconnect } + * after you're completely finished interacting with the server. + * Then you need to check the FTP reply code to see if the connection + * was successful. For example: + *

+ *    boolean error = false;
+ *    try {
+ *      int reply;
+ *      ftp.connect("ftp.foobar.com");
+ *      System.out.println("Connected to " + server + ".");
+ *      System.out.print(ftp.getReplyString());
+ *
+ *      // After connection attempt, you should check the reply code to verify
+ *      // success.
+ *      reply = ftp.getReplyCode();
+ *
+ *      if(!FTPReply.isPositiveCompletion(reply)) {
+ *        ftp.disconnect();
+ *        System.err.println("FTP server refused connection.");
+ *        System.exit(1);
+ *      }
+ *      ... // transfer files
+ *      ftp.logout();
+ *    } catch(IOException e) {
+ *      error = true;
+ *      e.printStackTrace();
+ *    } finally {
+ *      if(ftp.isConnected()) {
+ *        try {
+ *          ftp.disconnect();
+ *        } catch(IOException ioe) {
+ *          // do nothing
+ *        }
+ *      }
+ *      System.exit(error ? 1 : 0);
+ *    }
+ * 
+ *

+ * Immediately after connecting is the only real time you need to check the + * reply code (because connect is of type void). The convention for all the + * FTP command methods in FTPClient is such that they either return a + * boolean value or some other value. + * The boolean methods return true on a successful completion reply from + * the FTP server and false on a reply resulting in an error condition or + * failure. The methods returning a value other than boolean return a value + * containing the higher level data produced by the FTP command, or null if a + * reply resulted in an error condition or failure. If you want to access + * the exact FTP reply code causing a success or failure, you must call + * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after + * a success or failure. + *

+ * The default settings for FTPClient are for it to use + * FTP.ASCII_FILE_TYPE , + * FTP.NON_PRINT_TEXT_FORMAT , + * FTP.STREAM_TRANSFER_MODE , and + * FTP.FILE_STRUCTURE . The only file types directly supported + * are FTP.ASCII_FILE_TYPE and + * FTP.BINARY_FILE_TYPE . Because there are at least 4 + * different EBCDIC encodings, we have opted not to provide direct support + * for EBCDIC. To transfer EBCDIC and other unsupported file types you + * must create your own filter InputStreams and OutputStreams and wrap + * them around the streams returned or required by the FTPClient methods. + * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII} + * filter streams to provide transparent handling of ASCII files. We will + * consider incorporating EBCDIC support if there is enough demand. + *

+ * FTP.NON_PRINT_TEXT_FORMAT , + * FTP.STREAM_TRANSFER_MODE , and + * FTP.FILE_STRUCTURE are the only supported formats, + * transfer modes, and file structures. + *

+ * Because the handling of sockets on different platforms can differ + * significantly, the FTPClient automatically issues a new PORT command + * prior to every transfer requiring that the server connect to the client's + * data port. This ensures identical problem-free behavior on Windows, Unix, + * and Macintosh platforms. Additionally, it relieves programmers from + * having to issue the PORT command themselves and dealing with platform + * dependent issues. + *

+ * Additionally, for security purposes, all data connections to the + * client are verified to ensure that they originated from the intended + * party (host and port). If a data connection is initiated by an unexpected + * party, the command will close the socket and throw an IOException. You + * may disable this behavior with + * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}. + *

+ * You should keep in mind that the FTP server may choose to prematurely + * close a connection if the client has been idle for longer than a + * given time period (usually 900 seconds). The FTPClient class will detect a + * premature FTP server connection closing when it receives a + * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } + * response to a command. + * When that occurs, the FTP class method encountering that reply will throw + * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * . + * FTPConnectionClosedException + * is a subclass of IOException and therefore need not be + * caught separately, but if you are going to catch it separately, its + * catch block must appear before the more general IOException + * catch block. When you encounter an + * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} + * , you must disconnect the connection with + * {@link #disconnect disconnect() } to properly clean up the + * system resources used by FTPClient. Before disconnecting, you may check the + * last reply code and text with + * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode }, + * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString }, + * and + * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}. + * You may avoid server disconnections while the client is idle by + * periodicaly sending NOOP commands to the server. + *

+ * Rather than list it separately for each method, we mention here that + * every method communicating with the server and throwing an IOException + * can also throw a + * {@link org.apache.commons.net.MalformedServerReplyException} + * , which is a subclass + * of IOException. A MalformedServerReplyException will be thrown when + * the reply received from the server deviates enough from the protocol + * specification that it cannot be interpreted in a useful manner despite + * attempts to be as lenient as possible. + *

+ * Listing API Examples + * Both paged and unpaged examples of directory listings are available, + * as follows: + *

+ * Unpaged (whole list) access, using a parser accessible by auto-detect: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ * Paged access, using a parser not accessible by auto-detect. The class + * defined in the first parameter of initateListParsing should be derived + * from org.apache.commons.net.FTPFileEntryParser: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine =
+ *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ * Paged access, using a parser accessible by auto-detect: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine = f.initiateListParsing(directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ * For examples of using FTPClient on servers whose directory listings + *

    + *
  • use languages other than English
  • + *
  • use date formats other than the American English "standard" MM d yyyy
  • + *
  • are in different timezones and you need accurate timestamps for dependency checking + * as in Ant
  • + *
see {@link FTPClientConfig FTPClientConfig}. + *

+ * @author Daniel F. Savarese + * @author Rory Winston + * @see FTP + * @see FTPConnectionClosedException + * @see FTPFileEntryParser + * @see FTPFileEntryParserFactory + * @see DefaultFTPFileEntryParserFactory + * @see FTPClientConfig + * + * @see org.apache.commons.net.MalformedServerReplyException + **/ +public class FTPClient extends FTP +implements Configurable +{ + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between the client (local) and server and that the server + * should connect to the client's data port to initiate a data transfer. + * This is the default data connection mode when and FTPClient instance + * is created. + ***/ + public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0; + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between two remote servers and that the server + * the client is connected to should connect to the other server's + * data port to initiate a data transfer. + ***/ + public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1; + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between the client (local) and server and that the server + * is in passive mode, requiring the client to connect to the + * server's data port to initiate a transfer. + ***/ + public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2; + /*** + * A constant indicating the FTP session is expecting all transfers + * to occur between two remote servers and that the server + * the client is connected to is in passive mode, requiring the other + * server to connect to the first server's data port to initiate a data + * transfer. + ***/ + public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3; + + private int __dataConnectionMode, __dataTimeout; + private int __passivePort; + private String __passiveHost; + private int __fileType, __fileFormat, __fileStructure, __fileTransferMode; + private boolean __remoteVerificationEnabled; + private long __restartOffset; + private FTPFileEntryParserFactory __parserFactory; + private int __bufferSize; + private boolean __listHiddenFiles; + + // __systemName is a cached value that should not be referenced directly + // except when assigned in getSystemName and __initDefaults. + private String __systemName; + + // __entryParser is a cached value that should not be referenced directly + // except when assigned in listFiles(String, String) and __initDefaults. + private FTPFileEntryParser __entryParser; + + private FTPClientConfig __configuration; + + /** Pattern for PASV mode responses */ + private static String __parms = "\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}"; + private static java.util.regex.Pattern __parms_pat; + static { + __parms_pat = java.util.regex.Pattern.compile(__parms); + } + + /*** + * Default FTPClient constructor. Creates a new FTPClient instance + * with the data connection mode set to + * ACTIVE_LOCAL_DATA_CONNECTION_MODE , the file type + * set to FTP.ASCII_FILE_TYPE , the + * file format set to FTP.NON_PRINT_TEXT_FORMAT , + * the file structure set to FTP.FILE_STRUCTURE , and + * the transfer mode set to FTP.STREAM_TRANSFER_MODE . + ***/ + public FTPClient() + { + __initDefaults(); + __dataTimeout = -1; + __remoteVerificationEnabled = true; + __parserFactory = new DefaultFTPFileEntryParserFactory(); + __configuration = null; + __listHiddenFiles = false; + } + + + private void __initDefaults() + { + __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; + __passiveHost = null; + __passivePort = -1; + __fileType = FTP.ASCII_FILE_TYPE; + __fileStructure = FTP.FILE_STRUCTURE; + __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; + __fileTransferMode = FTP.STREAM_TRANSFER_MODE; + __restartOffset = 0; + __systemName = null; + __entryParser = null; + __bufferSize = Util.DEFAULT_COPY_BUFFER_SIZE; + } + + private String __parsePathname(String reply) + { + int begin, end; + + begin = reply.indexOf('"') + 1; + end = reply.indexOf('"', begin); + + return reply.substring(begin, end); + } + + + private void __parsePassiveModeReply(String reply) + throws MalformedServerReplyException + { + java.util.regex.Matcher m = __parms_pat.matcher(reply); + if (!m.find()) { + throw new MalformedServerReplyException( + "Could not parse passive host information.\nServer Reply: " + reply); + } + reply = m.group(); + String parts[] = m.group().split(","); + + __passiveHost = parts[0] + '.' + parts[1] + '.' + parts[2] + '.' + parts[3]; + + try + { + int oct1 = Integer.parseInt(parts[4]); + int oct2 = Integer.parseInt(parts[5]); + __passivePort = (oct1 << 8) | oct2; + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse passive host information.\nServer Reply: " + reply); + } + + } + + private boolean __storeFile(int command, String remote, InputStream local) + throws IOException + { + OutputStream output; + Socket socket; + + if ((socket = _openDataConnection_(command, remote)) == null) + return false; + + output = new BufferedOutputStream(socket.getOutputStream(), + getBufferSize() + ); + if (__fileType == ASCII_FILE_TYPE) + output = new ToNetASCIIOutputStream(output); + // Treat everything else as binary for now + try + { + Util.copyStream(local, output, getBufferSize(), + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, + false); + } + catch (IOException e) + { + try + { + socket.close(); + } + catch (IOException f) + {} + throw e; + } + output.close(); + socket.close(); + return completePendingCommand(); + } + + private OutputStream __storeFileStream(int command, String remote) + throws IOException + { + OutputStream output; + Socket socket; + + if ((socket = _openDataConnection_(command, remote)) == null) + return null; + + output = socket.getOutputStream(); + if (__fileType == ASCII_FILE_TYPE) { + // We buffer ascii transfers because the buffering has to + // be interposed between ToNetASCIIOutputSream and the underlying + // socket output stream. We don't buffer binary transfers + // because we don't want to impose a buffering policy on the + // programmer if possible. Programmers can decide on their + // own if they want to wrap the SocketOutputStream we return + // for file types other than ASCII. + output = new BufferedOutputStream(output, + getBufferSize()); + output = new ToNetASCIIOutputStream(output); + + } + return new org.apache.commons.net.io.SocketOutputStream(socket, output); + } + + + /** + * Establishes a data connection with the FTP server, returning + * a Socket for the connection if successful. If a restart + * offset has been set with {@link #setRestartOffset(long)}, + * a REST command is issued to the server with the offset as + * an argument before establishing the data connection. Active + * mode connections also cause a local PORT command to be issued. + *

+ * @param command The text representation of the FTP command to send. + * @param arg The arguments to the FTP command. If this parameter is + * set to null, then the command is sent with no argument. + * @return A Socket corresponding to the established data connection. + * Null is returned if an FTP protocol error is reported at + * any point during the establishment and initialization of + * the connection. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + protected Socket _openDataConnection_(int command, String arg) + throws IOException + { + Socket socket; + + if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE && + __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) + return null; + + if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) + { + ServerSocket server; + server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); + + if (!FTPReply.isPositiveCompletion(port(getLocalAddress(), + server.getLocalPort()))) + { + server.close(); + return null; + } + + if ((__restartOffset > 0) && !restart(__restartOffset)) + { + server.close(); + return null; + } + + if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) + { + server.close(); + return null; + } + + // For now, let's just use the data timeout value for waiting for + // the data connection. It may be desirable to let this be a + // separately configurable value. In any case, we really want + // to allow preventing the accept from blocking indefinitely. + if (__dataTimeout >= 0) + server.setSoTimeout(__dataTimeout); + try { + socket = server.accept(); + } finally { + server.close(); + } + } + else + { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE + + if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) + return null; + + __parsePassiveModeReply(_replyLines.get(_replyLines.size() - 1)); + + socket = _socketFactory_.createSocket(__passiveHost, __passivePort); + if ((__restartOffset > 0) && !restart(__restartOffset)) + { + socket.close(); + return null; + } + + if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) + { + socket.close(); + return null; + } + } + + if (__remoteVerificationEnabled && !verifyRemote(socket)) + { + InetAddress host1, host2; + + host1 = socket.getInetAddress(); + host2 = getRemoteAddress(); + + socket.close(); + + throw new IOException( + "Host attempting data connection " + host1.getHostAddress() + + " is not same as server " + host2.getHostAddress()); + } + + if (__dataTimeout >= 0) + socket.setSoTimeout(__dataTimeout); + + return socket; + } + + + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + __initDefaults(); + } + + + /*** + * Sets the timeout in milliseconds to use when reading from the + * data connection. This timeout will be set immediately after + * opening the data connection. + *

+ * @param timeout The default timeout in milliseconds that is used when + * opening a data connection socket. + ***/ + public void setDataTimeout(int timeout) + { + __dataTimeout = timeout; + } + + /** + * set the factory used for parser creation to the supplied factory object. + * + * @param parserFactory + * factory object used to create FTPFileEntryParsers + * + * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + */ + public void setParserFactory(FTPFileEntryParserFactory parserFactory) { + __parserFactory = parserFactory; + } + + + /*** + * Closes the connection to the FTP server and restores + * connection parameters to the default values. + *

+ * @exception IOException If an error occurs while disconnecting. + ***/ + @Override + public void disconnect() throws IOException + { + super.disconnect(); + __initDefaults(); + } + + + /*** + * Enable or disable verification that the remote host taking part + * of a data connection is the same as the host to which the control + * connection is attached. The default is for verification to be + * enabled. You may set this value at any time, whether the + * FTPClient is currently connected or not. + *

+ * @param enable True to enable verification, false to disable verification. + ***/ + public void setRemoteVerificationEnabled(boolean enable) + { + __remoteVerificationEnabled = enable; + } + + /*** + * Return whether or not verification of the remote host participating + * in data connections is enabled. The default behavior is for + * verification to be enabled. + *

+ * @return True if verification is enabled, false if not. + ***/ + public boolean isRemoteVerificationEnabled() + { + return __remoteVerificationEnabled; + } + + /*** + * Login to the FTP server using the provided username and password. + *

+ * @param username The username to login under. + * @param password The password to use. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean login(String username, String password) throws IOException + { + user(username); + + if (FTPReply.isPositiveCompletion(_replyCode)) + return true; + + // If we get here, we either have an error code, or an intermmediate + // reply requesting password. + if (!FTPReply.isPositiveIntermediate(_replyCode)) + return false; + + return FTPReply.isPositiveCompletion(pass(password)); + } + + + /*** + * Login to the FTP server using the provided username, password, + * and account. If no account is required by the server, only + * the username and password, the account information is not used. + *

+ * @param username The username to login under. + * @param password The password to use. + * @param account The account to use. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean login(String username, String password, String account) + throws IOException + { + user(username); + + if (FTPReply.isPositiveCompletion(_replyCode)) + return true; + + // If we get here, we either have an error code, or an intermmediate + // reply requesting password. + if (!FTPReply.isPositiveIntermediate(_replyCode)) + return false; + + pass(password); + + if (FTPReply.isPositiveCompletion(_replyCode)) + return true; + + if (!FTPReply.isPositiveIntermediate(_replyCode)) + return false; + + return FTPReply.isPositiveCompletion(acct(account)); + } + + /*** + * Logout of the FTP server by sending the QUIT command. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean logout() throws IOException + { + return FTPReply.isPositiveCompletion(quit()); + } + + + /*** + * Change the current working directory of the FTP session. + *

+ * @param pathname The new current working directory. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean changeWorkingDirectory(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(cwd(pathname)); + } + + + /*** + * Change to the parent directory of the current working directory. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean changeToParentDirectory() throws IOException + { + return FTPReply.isPositiveCompletion(cdup()); + } + + + /*** + * Issue the FTP SMNT command. + *

+ * @param pathname The pathname to mount. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean structureMount(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(smnt(pathname)); + } + + /*** + * Reinitialize the FTP session. Not all FTP servers support this + * command, which issues the FTP REIN command. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + boolean reinitialize() throws IOException + { + rein(); + + if (FTPReply.isPositiveCompletion(_replyCode) || + (FTPReply.isPositivePreliminary(_replyCode) && + FTPReply.isPositiveCompletion(getReply()))) + { + + __initDefaults(); + + return true; + } + + return false; + } + + + /*** + * Set the current data connection mode to + * ACTIVE_LOCAL_DATA_CONNECTION_MODE. No communication + * with the FTP server is conducted, but this causes all future data + * transfers to require the FTP server to connect to the client's + * data port. Additionally, to accommodate differences between socket + * implementations on different platforms, this method causes the + * client to issue a PORT command before every data transfer. + ***/ + public void enterLocalActiveMode() + { + __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; + __passiveHost = null; + __passivePort = -1; + } + + + /*** + * Set the current data connection mode to + * PASSIVE_LOCAL_DATA_CONNECTION_MODE . Use this + * method only for data transfers between the client and server. + * This method causes a PASV command to be issued to the server + * before the opening of every data connection, telling the server to + * open a data port to which the client will connect to conduct + * data transfers. The FTPClient will stay in + * PASSIVE_LOCAL_DATA_CONNECTION_MODE until the + * mode is changed by calling some other method such as + * {@link #enterLocalActiveMode enterLocalActiveMode() } + ***/ + public void enterLocalPassiveMode() + { + __dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE; + // These will be set when just before a data connection is opened + // in _openDataConnection_() + __passiveHost = null; + __passivePort = -1; + } + + + /*** + * Set the current data connection mode to + * ACTIVE_REMOTE_DATA_CONNECTION . Use this method only + * for server to server data transfers. This method issues a PORT + * command to the server, indicating the other server and port to which + * it should connect for data transfers. You must call this method + * before EVERY server to server transfer attempt. The FTPClient will + * NOT automatically continue to issue PORT commands. You also + * must remember to call + * {@link #enterLocalActiveMode enterLocalActiveMode() } if you + * wish to return to the normal data connection mode. + *

+ * @param host The passive mode server accepting connections for data + * transfers. + * @param port The passive mode server's data port. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean enterRemoteActiveMode(InetAddress host, int port) + throws IOException + { + if (FTPReply.isPositiveCompletion(port(host, port))) + { + __dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE; + __passiveHost = null; + __passivePort = -1; + return true; + } + return false; + } + + /*** + * Set the current data connection mode to + * PASSIVE_REMOTE_DATA_CONNECTION_MODE . Use this + * method only for server to server data transfers. + * This method issues a PASV command to the server, telling it to + * open a data port to which the active server will connect to conduct + * data transfers. You must call this method + * before EVERY server to server transfer attempt. The FTPClient will + * NOT automatically continue to issue PASV commands. You also + * must remember to call + * {@link #enterLocalActiveMode enterLocalActiveMode() } if you + * wish to return to the normal data connection mode. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean enterRemotePassiveMode() throws IOException + { + if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) + return false; + + __dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE; + __parsePassiveModeReply(_replyLines.get(0)); + + return true; + } + + /*** + * Returns the hostname or IP address (in the form of a string) returned + * by the server when entering passive mode. If not in passive mode, + * returns null. This method only returns a valid value AFTER a + * data connection has been opened after a call to + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + * This is because FTPClient sends a PASV command to the server only + * just before opening a data connection, and not when you call + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + *

+ * @return The passive host name if in passive mode, otherwise null. + ***/ + public String getPassiveHost() + { + return __passiveHost; + } + + /*** + * If in passive mode, returns the data port of the passive host. + * This method only returns a valid value AFTER a + * data connection has been opened after a call to + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + * This is because FTPClient sends a PASV command to the server only + * just before opening a data connection, and not when you call + * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. + *

+ * @return The data port of the passive server. If not in passive + * mode, undefined. + ***/ + public int getPassivePort() + { + return __passivePort; + } + + + /*** + * Returns the current data connection mode (one of the + * _DATA_CONNECTION_MODE constants. + *

+ * @return The current data connection mode (one of the + * _DATA_CONNECTION_MODE constants. + ***/ + public int getDataConnectionMode() + { + return __dataConnectionMode; + } + + + /*** + * Sets the file type to be transferred. This should be one of + * FTP.ASCII_FILE_TYPE , FTP.BINARY_FILE_TYPE, + * etc. The file type only needs to be set when you want to change the + * type. After changing it, the new type stays in effect until you change + * it again. The default file type is FTP.ASCII_FILE_TYPE + * if this method is never called. + *

+ * @param fileType The _FILE_TYPE constant indcating the + * type of file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileType(int fileType) throws IOException + { + if (FTPReply.isPositiveCompletion(type(fileType))) + { + __fileType = fileType; + __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; + return true; + } + return false; + } + + + /*** + * Sets the file type to be transferred and the format. The type should be + * one of FTP.ASCII_FILE_TYPE , + * FTP.BINARY_FILE_TYPE , etc. The file type only needs to + * be set when you want to change the type. After changing it, the new + * type stays in effect until you change it again. The default file type + * is FTP.ASCII_FILE_TYPE if this method is never called. + * The format should be one of the FTP class TEXT_FORMAT + * constants, or if the type is FTP.LOCAL_FILE_TYPE , the + * format should be the byte size for that type. The default format + * is FTP.NON_PRINT_TEXT_FORMAT if this method is never + * called. + *

+ * @param fileType The _FILE_TYPE constant indcating the + * type of file. + * @param formatOrByteSize The format of the file (one of the + * _FORMAT constants. In the case of + * LOCAL_FILE_TYPE, the byte size. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileType(int fileType, int formatOrByteSize) + throws IOException + { + if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) + { + __fileType = fileType; + __fileFormat = formatOrByteSize; + return true; + } + return false; + } + + + /*** + * Sets the file structure. The default structure is + * FTP.FILE_STRUCTURE if this method is never called. + *

+ * @param structure The structure of the file (one of the FTP class + * _STRUCTURE constants). + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileStructure(int structure) throws IOException + { + if (FTPReply.isPositiveCompletion(stru(structure))) + { + __fileStructure = structure; + return true; + } + return false; + } + + + /*** + * Sets the transfer mode. The default transfer mode + * FTP.STREAM_TRANSFER_MODE if this method is never called. + *

+ * @param mode The new transfer mode to use (one of the FTP class + * _TRANSFER_MODE constants). + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean setFileTransferMode(int mode) throws IOException + { + if (FTPReply.isPositiveCompletion(mode(mode))) + { + __fileTransferMode = mode; + return true; + } + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to retrieve a given file from + * the other server. + *

+ * @param filename The name of the file to retrieve. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteRetrieve(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(retr(filename)); + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to store a file on + * the other server using the given filename. The other server must + * have had a remoteRetrieve issued to it by another + * FTPClient. + *

+ * @param filename The name to call the file that is to be stored. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteStore(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stor(filename)); + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to store a file on + * the other server using a unique filename based on the given filename. + * The other server must have had a remoteRetrieve issued + * to it by another FTPClient. + *

+ * @param filename The name on which to base the filename of the file + * that is to be stored. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteStoreUnique(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stou(filename)); + return false; + } + + + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to store a file on + * the other server using a unique filename. + * The other server must have had a remoteRetrieve issued + * to it by another FTPClient. Many FTP servers require that a base + * filename be given from which the unique filename can be derived. For + * those servers use the other version of remoteStoreUnique + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteStoreUnique() throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stou()); + return false; + } + + // For server to server transfers + /*** + * Initiate a server to server file transfer. This method tells the + * server to which the client is connected to append to a given file on + * the other server. The other server must have had a + * remoteRetrieve issued to it by another FTPClient. + *

+ * @param filename The name of the file to be appended to, or if the + * file does not exist, the name to call the file being stored. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean remoteAppend(String filename) throws IOException + { + if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || + __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) + return FTPReply.isPositivePreliminary(stor(filename)); + return false; + } + + /*** + * There are a few FTPClient methods that do not complete the + * entire sequence of FTP commands to complete a transaction. These + * commands require some action by the programmer after the reception + * of a positive intermediate command. After the programmer's code + * completes its actions, it must call this method to receive + * the completion reply from the server and verify the success of the + * entire transaction. + *

+ * For example, + *

+     * InputStream input;
+     * OutputStream output;
+     * input  = new FileInputStream("foobaz.txt");
+     * output = ftp.storeFileStream("foobar.txt")
+     * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
+     *     input.close();
+     *     output.close();
+     *     ftp.logout();
+     *     ftp.disconnect();
+     *     System.err.println("File transfer failed.");
+     *     System.exit(1);
+     * }
+     * Util.copyStream(input, output);
+     * input.close();
+     * output.close();
+     * // Must call completePendingCommand() to finish command.
+     * if(!ftp.completePendingCommand()) {
+     *     ftp.logout();
+     *     ftp.disconnect();
+     *     System.err.println("File transfer failed.");
+     *     System.exit(1);
+     * }
+     * 
+ *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean completePendingCommand() throws IOException + { + return FTPReply.isPositiveCompletion(getReply()); + } + + + /*** + * Retrieves a named file from the server and writes it to the given + * OutputStream. This method does NOT close the given OutputStream. + * If the current file type is ASCII, line separators in the file are + * converted to the local representation. + *

+ * @param remote The name of the remote file. + * @param local The local OutputStream to which to write the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean retrieveFile(String remote, OutputStream local) + throws IOException + { + InputStream input; + Socket socket; + + if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) + return false; + + input = new BufferedInputStream(socket.getInputStream(), + getBufferSize()); + if (__fileType == ASCII_FILE_TYPE) + input = new FromNetASCIIInputStream(input); + // Treat everything else as binary for now + try + { + Util.copyStream(input, local, getBufferSize(), + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, + false); + } + catch (IOException e) + { + try + { + socket.close(); + } + catch (IOException f) + {} + throw e; + } + socket.close(); + return completePendingCommand(); + } + + /*** + * Returns an InputStream from which a named file from the server + * can be read. If the current file type is ASCII, the returned + * InputStream will convert line separators in the file to + * the local representation. You must close the InputStream when you + * finish reading from it. The InputStream itself will take care of + * closing the parent data connection socket upon being closed. To + * finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name of the remote file. + * @return An InputStream from which the remote file can be read. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public InputStream retrieveFileStream(String remote) throws IOException + { + InputStream input; + Socket socket; + + if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) + return null; + + input = socket.getInputStream(); + if (__fileType == ASCII_FILE_TYPE) { + // We buffer ascii transfers because the buffering has to + // be interposed between FromNetASCIIOutputSream and the underlying + // socket input stream. We don't buffer binary transfers + // because we don't want to impose a buffering policy on the + // programmer if possible. Programmers can decide on their + // own if they want to wrap the SocketInputStream we return + // for file types other than ASCII. + input = new BufferedInputStream(input, + getBufferSize()); + input = new FromNetASCIIInputStream(input); + } + return new org.apache.commons.net.io.SocketInputStream(socket, input); + } + + + /*** + * Stores a file on the server using the given name and taking input + * from the given InputStream. This method does NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param remote The name to give the remote file. + * @param local The local InputStream from which to read the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean storeFile(String remote, InputStream local) + throws IOException + { + return __storeFile(FTPCommand.STOR, remote, local); + } + + + /*** + * Returns an OutputStream through which data can be written to store + * a file on the server using the given name. If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name to give the remote file. + * @return An OutputStream through which the remote file can be written. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public OutputStream storeFileStream(String remote) throws IOException + { + return __storeFileStream(FTPCommand.STOR, remote); + } + + /*** + * Appends to a file on the server with the given name, taking input + * from the given InputStream. This method does NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param remote The name of the remote file. + * @param local The local InputStream from which to read the data to + * be appended to the remote file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean appendFile(String remote, InputStream local) + throws IOException + { + return __storeFile(FTPCommand.APPE, remote, local); + } + + /*** + * Returns an OutputStream through which data can be written to append + * to a file on the server with the given name. If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name of the remote file. + * @return An OutputStream through which the remote file can be appended. + * If the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public OutputStream appendFileStream(String remote) throws IOException + { + return __storeFileStream(FTPCommand.APPE, remote); + } + + /*** + * Stores a file on the server using a unique name derived from the + * given name and taking input + * from the given InputStream. This method does NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param remote The name on which to base the unique name given to + * the remote file. + * @param local The local InputStream from which to read the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean storeUniqueFile(String remote, InputStream local) + throws IOException + { + return __storeFile(FTPCommand.STOU, remote, local); + } + + + /*** + * Returns an OutputStream through which data can be written to store + * a file on the server using a unique name derived from the given name. + * If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @param remote The name on which to base the unique name given to + * the remote file. + * @return An OutputStream through which the remote file can be written. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public OutputStream storeUniqueFileStream(String remote) throws IOException + { + return __storeFileStream(FTPCommand.STOU, remote); + } + + /** + * Stores a file on the server using a unique name assigned by the + * server and taking input from the given InputStream. This method does + * NOT close the given + * InputStream. If the current file type is ASCII, line separators in + * the file are transparently converted to the NETASCII format (i.e., + * you should not attempt to create a special InputStream to do this). + *

+ * @param local The local InputStream from which to read the file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception CopyStreamException If an I/O error occurs while actually + * transferring the file. The CopyStreamException allows you to + * determine the number of bytes transferred and the IOException + * causing the error. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public boolean storeUniqueFile(InputStream local) throws IOException + { + return __storeFile(FTPCommand.STOU, null, local); + } + + /** + * Returns an OutputStream through which data can be written to store + * a file on the server using a unique name assigned by the server. + * If the current file type + * is ASCII, the returned OutputStream will convert line separators in + * the file to the NETASCII format (i.e., you should not attempt to + * create a special OutputStream to do this). You must close the + * OutputStream when you finish writing to it. The OutputStream itself + * will take care of closing the parent data connection socket upon being + * closed. To finalize the file transfer you must call + * {@link #completePendingCommand completePendingCommand } and + * check its return value to verify success. + *

+ * @return An OutputStream through which the remote file can be written. If + * the data connection cannot be opened (e.g., the file does not + * exist), null is returned (in which case you may check the reply + * code to determine the exact reason for failure). + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public OutputStream storeUniqueFileStream() throws IOException + { + return __storeFileStream(FTPCommand.STOU, null); + } + + /*** + * Reserve a number of bytes on the server for the next file transfer. + *

+ * @param bytes The number of bytes which the server should allocate. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean allocate(int bytes) throws IOException + { + return FTPReply.isPositiveCompletion(allo(bytes)); + } + + + /** + * Reserve space on the server for the next file transfer. + *

+ * @param bytes The number of bytes which the server should allocate. + * @param recordSize The size of a file record. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public boolean allocate(int bytes, int recordSize) throws IOException + { + return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); + } + + + /*** + * Restart a STREAM_TRANSFER_MODE file transfer starting + * from the given offset. This will only work on FTP servers supporting + * the REST comand for the stream transfer mode. However, most FTP + * servers support this. Any subsequent file transfer will start + * reading or writing the remote file from the indicated offset. + *

+ * @param offset The offset into the remote file at which to start the + * next file transfer. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + private boolean restart(long offset) throws IOException + { + __restartOffset = 0; + return FTPReply.isPositiveIntermediate(rest(Long.toString(offset))); + } + + /*** + * Sets the restart offset. The restart command is sent to the server + * only before sending the file transfer command. When this is done, + * the restart marker is reset to zero. + *

+ * @param offset The offset into the remote file at which to start the + * next file transfer. This must be a value greater than or + * equal to zero. + ***/ + public void setRestartOffset(long offset) + { + if (offset >= 0) + __restartOffset = offset; + } + + /*** + * Fetches the restart offset. + *

+ * @return offset The offset into the remote file at which to start the + * next file transfer. + ***/ + public long getRestartOffset() + { + return __restartOffset; + } + + + + /*** + * Renames a remote file. + *

+ * @param from The name of the remote file to rename. + * @param to The new name of the remote file. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean rename(String from, String to) throws IOException + { + if (!FTPReply.isPositiveIntermediate(rnfr(from))) + return false; + + return FTPReply.isPositiveCompletion(rnto(to)); + } + + + /*** + * Abort a transfer in progress. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean abort() throws IOException + { + return FTPReply.isPositiveCompletion(abor()); + } + + /*** + * Deletes a file on the FTP server. + *

+ * @param pathname The pathname of the file to be deleted. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean deleteFile(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(dele(pathname)); + } + + + /*** + * Removes a directory on the FTP server (if empty). + *

+ * @param pathname The pathname of the directory to remove. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean removeDirectory(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(rmd(pathname)); + } + + + /*** + * Creates a new subdirectory on the FTP server in the current directory + * (if a relative pathname is given) or where specified (if an absolute + * pathname is given). + *

+ * @param pathname The pathname of the directory to create. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean makeDirectory(String pathname) throws IOException + { + return FTPReply.isPositiveCompletion(mkd(pathname)); + } + + + /*** + * Returns the pathname of the current working directory. + *

+ * @return The pathname of the current working directory. If it cannot + * be obtained, returns null. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String printWorkingDirectory() throws IOException + { + if (pwd() != FTPReply.PATHNAME_CREATED) + return null; + + return __parsePathname(_replyLines.get( _replyLines.size() - 1)); + } + + + /** + * Send a site specific command. + * @param arguments The site specific command and arguments. + * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public boolean sendSiteCommand(String arguments) throws IOException + { + return FTPReply.isPositiveCompletion(site(arguments)); + } + + + /*** + * Fetches the system type name from the server and returns the string. + * This value is cached for the duration of the connection after the + * first call to this method. In other words, only the first time + * that you invoke this method will it issue a SYST command to the + * FTP server. FTPClient will remember the value and return the + * cached value until a call to disconnect. + *

+ * @return The system type name obtained from the server. null if the + * information could not be obtained. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String getSystemName() throws IOException + { + //if (syst() == FTPReply.NAME_SYSTEM_TYPE) + // Technically, we should expect a NAME_SYSTEM_TYPE response, but + // in practice FTP servers deviate, so we soften the condition to + // a positive completion. + if (__systemName == null && FTPReply.isPositiveCompletion(syst())) + __systemName = _replyLines.get(_replyLines.size() - 1).substring(4); + + return __systemName; + } + + + /*** + * Fetches the system help information from the server and returns the + * full string. + *

+ * @return The system help string obtained from the server. null if the + * information could not be obtained. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String listHelp() throws IOException + { + if (FTPReply.isPositiveCompletion(help())) + return getReplyString(); + return null; + } + + + /** + * Fetches the help information for a given command from the server and + * returns the full string. + * @param command The command on which to ask for help. + * @return The command help string obtained from the server. null if the + * information could not be obtained. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + */ + public String listHelp(String command) throws IOException + { + if (FTPReply.isPositiveCompletion(help(command))) + return getReplyString(); + return null; + } + + + /*** + * Sends a NOOP command to the FTP server. This is useful for preventing + * server timeouts. + *

+ * @return True if successfully completed, false if not. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public boolean sendNoOp() throws IOException + { + return FTPReply.isPositiveCompletion(noop()); + } + + + /*** + * Obtain a list of filenames in a directory (or just the name of a given + * file, which is not particularly useful). This information is obtained + * through the NLST command. If the given pathname is a directory and + * contains no files, a zero length array is returned only + * if the FTP server returned a positive completion code, otherwise + * null is returned (the FTP server returned a 550 error No files found.). + * If the directory is not empty, an array of filenames in the directory is + * returned. If the pathname corresponds + * to a file, only that file will be listed. The server may or may not + * expand glob expressions. + *

+ * @param pathname The file or directory to list. + * @return The list of filenames contained in the given path. null if + * the list could not be obtained. If there are no filenames in + * the directory, a zero-length array is returned. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String[] listNames(String pathname) throws IOException + { + String line; + Socket socket; + BufferedReader reader; + ArrayList results; + + if ((socket = _openDataConnection_(FTPCommand.NLST, pathname)) == null) + return null; + + reader = + new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); + + results = new ArrayList(); + while ((line = reader.readLine()) != null) + results.add(line); + + reader.close(); + socket.close(); + + if (completePendingCommand()) + { + String[] names = new String[ results.size() ]; + return results.toArray(names); + } + + return null; + } + + + /*** + * Obtain a list of filenames in the current working directory + * This information is obtained through the NLST command. If the current + * directory contains no files, a zero length array is returned only + * if the FTP server returned a positive completion code, otherwise, + * null is returned (the FTP server returned a 550 error No files found.). + * If the directory is not empty, an array of filenames in the directory is + * returned. + *

+ * @return The list of filenames contained in the current working + * directory. null if the list could not be obtained. + * If there are no filenames in the directory, a zero-length array + * is returned. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String[] listNames() throws IOException + { + return listNames(null); + } + + + + /** + * Using the default system autodetect mechanism, obtain a + * list of file information for the current working directory + * or for just a single file. + *

+ * This information is obtained through the LIST command. The contents of + * the returned array is determined by the FTPFileEntryParser + * used. + *

+ * @param pathname The file or directory to list. Since the server may + * or may not expand glob expressions, using them here + * is not recommended and may well cause this method to + * fail. + * + * @return The list of file information contained in the given path in + * the format determined by the autodetection mechanism + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection + * as a result of the client being idle or some other + * reason causing the server to send FTP reply code 421. + * This exception may be caught either as an IOException + * or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply + * from the server. + * @exception ParserInitializationException + * Thrown if the parserKey parameter cannot be + * resolved by the selected parser factory. + * In the DefaultFTPEntryParserFactory, this will + * happen when parserKey is neither + * the fully qualified class name of a class + * implementing the interface + * org.apache.commons.net.ftp.FTPFileEntryParser + * nor a string containing one of the recognized keys + * mapping to such a parser or if class loader + * security issues prevent its being loaded. + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.FTPFileEntryParser + */ + public FTPFile[] listFiles(String pathname) + throws IOException + { + String key = null; + FTPListParseEngine engine = + initiateListParsing(key, pathname); + return engine.getFiles(); + + } + /** + * Using the default system autodetect mechanism, obtain a + * list of file information for the current working directory. + *

+ * This information is obtained through the LIST command. The contents of + * the returned array is determined by the FTPFileEntryParser + * used. + *

+ * @return The list of file information contained in the current directory + * in the format determined by the autodetection mechanism. + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection + * as a result of the client being idle or some other + * reason causing the server to send FTP reply code 421. + * This exception may be caught either as an IOException + * or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply + * from the server. + * @exception ParserInitializationException + * Thrown if the parserKey parameter cannot be + * resolved by the selected parser factory. + * In the DefaultFTPEntryParserFactory, this will + * happen when parserKey is neither + * the fully qualified class name of a class + * implementing the interface + * org.apache.commons.net.ftp.FTPFileEntryParser + * nor a string containing one of the recognized keys + * mapping to such a parser or if class loader + * security issues prevent its being loaded. + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory + * @see org.apache.commons.net.ftp.FTPFileEntryParser + */ + public FTPFile[] listFiles() + throws IOException + { + return listFiles((String) null); + } + + /** + * Using the default autodetect mechanism, initialize an FTPListParseEngine + * object containing a raw file information for the current working + * directory on the server + * This information is obtained through the LIST command. This object + * is then capable of being iterated to return a sequence of FTPFile + * objects with information filled in by the + * FTPFileEntryParser used. + *

+ * This method differs from using the listFiles() methods in that + * expensive FTPFile objects are not created until needed which may be + * an advantage on large lists. + * + * @return A FTPListParseEngine object that holds the raw information and + * is capable of providing parsed FTPFile objects, one for each file + * containing information contained in the given path in the format + * determined by the parser parameter. Null will be + * returned if a data connection cannot be opened. If the current working + * directory contains no files, an empty array will be the return. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @exception ParserInitializationException + * Thrown if the autodetect mechanism cannot + * resolve the type of system we are connected with. + * @see FTPListParseEngine + */ + public FTPListParseEngine initiateListParsing() + throws IOException + { + return initiateListParsing((String) null); + } + + /** + * Using the default autodetect mechanism, initialize an FTPListParseEngine + * object containing a raw file information for the supplied directory. + * This information is obtained through the LIST command. This object + * is then capable of being iterated to return a sequence of FTPFile + * objects with information filled in by the + * FTPFileEntryParser used. + *

+ * The server may or may not expand glob expressions. You should avoid + * using glob expressions because the return format for glob listings + * differs from server to server and will likely cause this method to fail. + *

+ * This method differs from using the listFiles() methods in that + * expensive FTPFile objects are not created until needed which may be + * an advantage on large lists. + *

+ *

+     *    FTPClient f=FTPClient();
+     *    f.connect(server);
+     *    f.login(username, password);
+     *    FTPListParseEngine engine = f.initiateListParsing(directory);
+     *
+     *    while (engine.hasNext()) {
+     *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+     *       //do whatever you want with these files, display them, etc.
+     *       //expensive FTPFile objects not created until needed.
+     *    }
+     * 
+ * + * @return A FTPListParseEngine object that holds the raw information and + * is capable of providing parsed FTPFile objects, one for each file + * containing information contained in the given path in the format + * determined by the parser parameter. Null will be + * returned if a data connection cannot be opened. If the current working + * directory contains no files, an empty array will be the return. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @exception ParserInitializationException + * Thrown if the autodetect mechanism cannot + * resolve the type of system we are connected with. + * @see FTPListParseEngine + */ + public FTPListParseEngine initiateListParsing( + String pathname) + throws IOException + { + String key = null; + return initiateListParsing(key, pathname); + } + + /** + * Using the supplied parser key, initialize an FTPListParseEngine + * object containing a raw file information for the supplied directory. + * This information is obtained through the LIST command. This object + * is then capable of being iterated to return a sequence of FTPFile + * objects with information filled in by the + * FTPFileEntryParser used. + *

+ * The server may or may not expand glob expressions. You should avoid + * using glob expressions because the return format for glob listings + * differs from server to server and will likely cause this method to fail. + *

+ * This method differs from using the listFiles() methods in that + * expensive FTPFile objects are not created until needed which may be + * an advantage on large lists. + * + * @param parserKey A string representing a designated code or fully-qualified + * class name of an FTPFileEntryParser that should be + * used to parse each server file listing. + * + * @return A FTPListParseEngine object that holds the raw information and + * is capable of providing parsed FTPFile objects, one for each file + * containing information contained in the given path in the format + * determined by the parser parameter. Null will be + * returned if a data connection cannot be opened. If the current working + * directory contains no files, an empty array will be the return. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @exception ParserInitializationException + * Thrown if the parserKey parameter cannot be + * resolved by the selected parser factory. + * In the DefaultFTPEntryParserFactory, this will + * happen when parserKey is neither + * the fully qualified class name of a class + * implementing the interface + * org.apache.commons.net.ftp.FTPFileEntryParser + * nor a string containing one of the recognized keys + * mapping to such a parser or if class loader + * security issues prevent its being loaded. + * @see FTPListParseEngine + */ + public FTPListParseEngine initiateListParsing( + String parserKey, String pathname) + throws IOException + { + // We cache the value to avoid creation of a new object every + // time a file listing is generated. + if(__entryParser == null) { + if (null != parserKey) { + // if a parser key was supplied in the parameters, + // use that to create the paraser + __entryParser = + __parserFactory.createFileEntryParser(parserKey); + + } else { + // if no parserKey was supplied, check for a configuration + // in the params, and if non-null, use that. + if (null != __configuration) { + __entryParser = + __parserFactory.createFileEntryParser(__configuration); + } else { + // if a parserKey hasn't been supplied, and a configuration + // hasn't been supplied, then autodetect by calling + // the SYST command and use that to choose the parser. + __entryParser = + __parserFactory.createFileEntryParser(getSystemName()); + } + } + } + + return initiateListParsing(__entryParser, pathname); + + } + + + /** + * private method through which all listFiles() and + * initiateListParsing methods pass once a parser is determined. + * + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException + * If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + * @see FTPListParseEngine + */ + private FTPListParseEngine initiateListParsing( + FTPFileEntryParser parser, String pathname) + throws IOException + { + Socket socket; + + FTPListParseEngine engine = new FTPListParseEngine(parser); + + if ((socket = _openDataConnection_(FTPCommand.LIST, getListArguments(pathname))) == null) + { + return engine; + } + + + try { + engine.readServerList(socket.getInputStream(), getControlEncoding()); + } + finally { + socket.close(); + } + + completePendingCommand(); + return engine; + } + + /** + * @since 2.0 + */ + protected String getListArguments(String pathname) { + if (getListHiddenFiles()) + { + StringBuffer sb = new StringBuffer(pathname.length() + 3); + sb.append("-a "); + sb.append(pathname); + return sb.toString(); + } + + return pathname; + } + + + /*** + * Issue the FTP STAT command to the server. + *

+ * @return The status information returned by the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String getStatus() throws IOException + { + if (FTPReply.isPositiveCompletion(stat())) + return getReplyString(); + return null; + } + + + /*** + * Issue the FTP STAT command to the server for a given pathname. This + * should produce a listing of the file or directory. + *

+ * @return The status information returned by the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending a + * command to the server or receiving a reply from the server. + ***/ + public String getStatus(String pathname) throws IOException + { + if (FTPReply.isPositiveCompletion(stat(pathname))) + return getReplyString(); + return null; + } + + + /** + * Issue the FTP MDTM command (not supported by all servers to retrieve the last + * modification time of a file. The modification string should be in the + * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in + * GMT, but not all FTP servers honour this. + * + * @param pathname The file path to query. + * @return A string representing the last file modification time in YYYYMMDDhhmmss format. + * @throws IOException if an I/O error occurs. + * @since 2.0 + */ + public String getModificationTime(String pathname) throws IOException { + if (FTPReply.isPositiveCompletion(mdtm(pathname))) + return getReplyString(); + return null; + } + + + /** + * Set the internal buffer size. + * + * @param bufSize The size of the buffer + */ + public void setBufferSize(int bufSize) { + __bufferSize = bufSize; + } + + /** + * Retrieve the current internal buffer size. + * @return The current buffer size. + */ + public int getBufferSize() { + return __bufferSize; + } + + + /** + * Implementation of the {@link Configurable Configurable} interface. + * In the case of this class, configuring merely makes the config object available for the + * factory methods that construct parsers. + * @param config {@link FTPClientConfig FTPClientConfig} object used to + * provide non-standard configurations to the parser. + * @since 1.4 + */ + public void configure(FTPClientConfig config) { + this.__configuration = config; + } + + /** + * You can set this to true if you would like to get hidden files when {@link #listFiles} too. + * A LIST -a will be issued to the ftp server. + * It depends on your ftp server if you need to call this method, also dont expect to get rid + * of hidden files if you call this method with "false". + * + * @param listHiddenFiles true if hidden files should be listed + * @since 2.0 + */ + public void setListHiddenFiles(boolean listHiddenFiles) { + this.__listHiddenFiles = listHiddenFiles; + } + + /** + * @see #setListHiddenFiles(boolean) + * @return the current state + * @since 2.0 + */ + public boolean getListHiddenFiles() { + return this.__listHiddenFiles; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/src/org/apache/commons/net/ftp/FTPClientConfig.java b/src/org/apache/commons/net/ftp/FTPClientConfig.java new file mode 100644 index 0000000..450eddc --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPClientConfig.java @@ -0,0 +1,580 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.text.DateFormatSymbols; +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; + +/** + *

+ * This class implements an alternate means of configuring the + * {@link org.apache.commons.net.ftp.FTPClient FTPClient} object and + * also subordinate objects which it uses. Any class implementing the + * {@link org.apache.commons.net.ftp.Configurable Configurable } + * interface can be configured by this object. + *

+ * In particular this class was designed primarily to support configuration + * of FTP servers which express file timestamps in formats and languages + * other than those for the US locale, which although it is the most common + * is not universal. Unfortunately, nothing in the FTP spec allows this to + * be determined in an automated way, so manual configuration such as this + * is necessary. + *

+ * This functionality was designed to allow existing clients to work exactly + * as before without requiring use of this component. This component should + * only need to be explicitly invoked by the user of this package for problem + * cases that previous implementations could not solve. + *

+ *

Examples of use of FTPClientConfig

+ * Use cases: + * You are trying to access a server that + *
    + *
  • lists files with timestamps that use month names in languages other + * than English
  • + *
  • lists files with timestamps that use date formats other + * than the American English "standard" MM dd yyyy
  • + *
  • is in different timezone and you need accurate timestamps for + * dependency checking as in Ant
  • + *
+ *

+ * Unpaged (whole list) access on a UNIX server that uses French month names + * but uses the "standard" MMM d yyyy date formatting + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
+ *    conf.setServerLanguageCode("fr");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ *

+ * Paged access on a UNIX server that uses Danish month names + * and "European" date formatting in Denmark's time zone, when you + * are in some other time zone. + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
+ *    conf.setServerLanguageCode("da");
+ *    conf.setDefaultDateFormat("d MMM yyyy");
+ *    conf.setRecentDateFormat("d MMM HH:mm");
+ *    conf.setTimeZoneId("Europe/Copenhagen");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine =
+ *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ *

+ * Unpaged (whole list) access on a VMS server that uses month names + * in a language not {@link #getSupportedLanguageCodes() supported} by the system. + * but uses the "standard" MMM d yyyy date formatting + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS);
+ *    conf.setShortMonthNames(
+ *        "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ *

+ * Unpaged (whole list) access on a Windows-NT server in a different time zone. + * (Note, since the NT Format uses numeric date formatting, language issues + * are irrelevant here). + *

+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
+ *    conf.setTimeZoneId("America/Denver");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ * Unpaged (whole list) access on a Windows-NT server in a different time zone + * but which has been configured to use a unix-style listing format. + *
+ *    FTPClient f=FTPClient();
+ *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
+ *    conf.setTimeZoneId("America/Denver");
+ *    f.configure(conf);
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = listFiles(directory);
+ * 
+ *

+ * @since 1.4 + * @see org.apache.commons.net.ftp.Configurable + * @see org.apache.commons.net.ftp.FTPClient + * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) + * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl + */ +public class FTPClientConfig +{ + + /** + * Identifier by which a unix-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_UNIX = "UNIX"; + + /** + * Identifier by which a vms-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_VMS = "VMS"; + + /** + * Identifier by which a WindowsNT-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_NT = "WINDOWS"; + + /** + * Identifier by which an OS/2-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_OS2 = "OS/2"; + + /** + * Identifier by which an OS/400-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_OS400 = "OS/400"; + + /** + * Identifier by which an AS/400-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_AS400 = "AS/400"; + + /** + * Identifier by which an MVS-based ftp server is known throughout + * the commons-net ftp system. + */ + public static final String SYST_MVS = "MVS"; + + /** + * Some servers return an "UNKNOWN Type: L8" message + * in response to the SYST command. We set these to be a Unix-type system. + * This may happen if the ftpd in question was compiled without system + * information. + * + * NET-230 - Updated to be UPPERCASE so that the check done in + * createFileEntryParser will succeed. + * + * @since 1.5 + */ + public static final String SYST_L8 = "TYPE: L8"; + + /** + * Identifier by which an Netware-based ftp server is known throughout + * the commons-net ftp system. + * + * @since 1.5 + */ + public static final String SYST_NETWARE = "NETWARE"; + + private final String serverSystemKey; + private String defaultDateFormatStr = null; + private String recentDateFormatStr = null; + private boolean lenientFutureDates = false; + private String serverLanguageCode = null; + private String shortMonthNames = null; + private String serverTimeZoneId = null; + + + /** + * The main constructor for an FTPClientConfig object + * @param systemKey key representing system type of the server being + * connected to. See {@link #getServerSystemKey() serverSystemKey} + */ + public FTPClientConfig(String systemKey) { + this.serverSystemKey = systemKey; + } + + /** + * Convenience constructor mainly for use in testing. + * Constructs a UNIX configuration. + */ + public FTPClientConfig() { + this(SYST_UNIX); + } + + /** + * Constructor which allows setting of all member fields + * @param systemKey key representing system type of the server being + * connected to. See + * {@link #getServerSystemKey() serverSystemKey} + * @param defaultDateFormatStr See + * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} + * @param recentDateFormatStr See + * {@link #setRecentDateFormatStr(String) recentDateFormatStr} + * @param serverLanguageCode See + * {@link #setServerLanguageCode(String) serverLanguageCode} + * @param shortMonthNames See + * {@link #setShortMonthNames(String) shortMonthNames} + * @param serverTimeZoneId See + * {@link #setServerTimeZoneId(String) serverTimeZoneId} + */ + public FTPClientConfig(String systemKey, + String defaultDateFormatStr, + String recentDateFormatStr, + String serverLanguageCode, + String shortMonthNames, + String serverTimeZoneId) + { + this(systemKey); + this.defaultDateFormatStr = defaultDateFormatStr; + this.recentDateFormatStr = recentDateFormatStr; + this.serverLanguageCode = serverLanguageCode; + this.shortMonthNames = shortMonthNames; + this.serverTimeZoneId = serverTimeZoneId; + } + + private static Map LANGUAGE_CODE_MAP = new TreeMap(); + static { + + // if there are other commonly used month name encodings which + // correspond to particular locales, please add them here. + + + + // many locales code short names for months as all three letters + // these we handle simply. + LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); + LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); + LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); + LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish + LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese + LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish + LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish + LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian + LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch + LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian + LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian + LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian + LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak + LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian + + + // some don't + LANGUAGE_CODE_MAP.put("fr", + "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french + + } + + /** + * Getter for the serverSystemKey property. This property + * specifies the general type of server to which the client connects. + * Should be either one of the FTPClientConfig.SYST_* codes + * or else the fully qualified class name of a parser implementing both + * the FTPFileEntryParser and Configurable + * interfaces. + * @return Returns the serverSystemKey property. + */ + public String getServerSystemKey() { + return serverSystemKey; + } + + /** + * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} + * property. + * @return Returns the defaultDateFormatStr property. + */ + public String getDefaultDateFormatStr() { + return defaultDateFormatStr; + } + + /** + * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. + * @return Returns the recentDateFormatStr property. + */ + + public String getRecentDateFormatStr() { + return recentDateFormatStr; + } + + /** + * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. + * @return Returns the serverTimeZoneId property. + */ + public String getServerTimeZoneId() { + return serverTimeZoneId; + } + + /** + *

+ * getter for the {@link #setShortMonthNames(String) shortMonthNames} + * property. + *

+ * @return Returns the shortMonthNames. + */ + public String getShortMonthNames() { + return shortMonthNames; + } + + /** + *

+ * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. + *

+ * @return Returns the serverLanguageCode property. + */ + public String getServerLanguageCode() { + return serverLanguageCode; + } + + /** + *

+ * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. + *

+ * @return Returns the lenientFutureDates. + * @since 1.5 + */ + public boolean isLenientFutureDates() { + return lenientFutureDates; + } + /** + *

+ * setter for the defaultDateFormatStr property. This property + * specifies the main date format that will be used by a parser configured + * by this configuration to parse file timestamps. If this is not + * specified, such a parser will use as a default value, the most commonly + * used format which will be in as used in en_US locales. + *

+ * This should be in the format described for + * java.text.SimpleDateFormat. + * property. + *

+ * @param defaultDateFormatStr The defaultDateFormatStr to set. + */ + public void setDefaultDateFormatStr(String defaultDateFormatStr) { + this.defaultDateFormatStr = defaultDateFormatStr; + } + + /** + *

+ * setter for the recentDateFormatStr property. This property + * specifies a secondary date format that will be used by a parser + * configured by this configuration to parse file timestamps, typically + * those less than a year old. If this is not specified, such a parser + * will not attempt to parse using an alternate format. + *

+ * This is used primarily in unix-based systems. + *

+ * This should be in the format described for + * java.text.SimpleDateFormat. + *

+ * @param recentDateFormatStr The recentDateFormatStr to set. + */ + public void setRecentDateFormatStr(String recentDateFormatStr) { + this.recentDateFormatStr = recentDateFormatStr; + } + + /** + *

+ * setter for the lenientFutureDates property. This boolean property + * (default: false) only has meaning when a + * {@link #setRecentDateFormatStr(String) recentDateFormatStr} property + * has been set. In that case, if this property is set true, then the + * parser, when it encounters a listing parseable with the recent date + * format, will only consider a date to belong to the previous year if + * it is more than one day in the future. This will allow all + * out-of-synch situations (whether based on "slop" - i.e. servers simply + * out of synch with one another or because of time zone differences - + * but in the latter case it is highly recommended to use the + * {@link #setServerTimeZoneId(String) serverTimeZoneId} property + * instead) to resolve correctly. + *

+ * This is used primarily in unix-based systems. + *

+ * @param lenientFutureDates set true to compensate for out-of-synch + * conditions. + */ + public void setLenientFutureDates(boolean lenientFutureDates) { + this.lenientFutureDates = lenientFutureDates; + } + /** + *

+ * setter for the serverTimeZoneId property. This property + * allows a time zone to be specified corresponding to that known to be + * used by an FTP server in file listings. This might be particularly + * useful to clients such as Ant that try to use these timestamps for + * dependency checking. + *

+ * This should be one of the identifiers used by + * java.util.TimeZone to refer to time zones, for example, + * America/Chicago or Asia/Rangoon. + *

+ * @param serverTimeZoneId The serverTimeZoneId to set. + */ + public void setServerTimeZoneId(String serverTimeZoneId) { + this.serverTimeZoneId = serverTimeZoneId; + } + + /** + *

+ * setter for the shortMonthNames property. + * This property allows the user to specify a set of month names + * used by the server that is different from those that may be + * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} + * property. + *

+ * This should be a string containing twelve strings each composed of + * three characters, delimited by pipe (|) characters. Currently, + * only 8-bit ASCII characters are known to be supported. For example, + * a set of month names used by a hypothetical Icelandic FTP server might + * conceivably be specified as + * "jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des". + *

+ * @param shortMonthNames The value to set to the shortMonthNames property. + */ + public void setShortMonthNames(String shortMonthNames) { + this.shortMonthNames = shortMonthNames; + } + + /** + *

+ * setter for the serverLanguageCode property. This property allows + * user to specify a + * + * two-letter ISO-639 language code that will be used to + * configure the set of month names used by the file timestamp parser. + * If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} + * is specified, parsing will assume English month names, which may or + * may not be significant, depending on whether the date format(s) + * specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} + * and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using + * numeric or alphabetic month names. + *

+ *

If the code supplied is not supported here, en_US + * month names will be used. We are supporting here those language + * codes which, when a java.util.Locale is constucted + * using it, and a java.text.SimpleDateFormat is + * constructed using that Locale, the array returned by the + * SimpleDateFormat's getShortMonths() method consists + * solely of three 8-bit ASCII character strings. Additionally, + * languages which do not meet this requirement are included if a + * common alternative set of short month names is known to be used. + * This means that users who can tell us of additional such encodings + * may get them added to the list of supported languages by contacting + * the jakarta-commons-net team. + *

+ *

+ * Please note that this attribute will NOT be used to determine a + * locale-based date format for the language. + * Experience has shown that many if not most FTP servers outside the + * United States employ the standard en_US date format + * orderings of MMM d yyyy and MMM d HH:mm + * and attempting to deduce this automatically here would cause more + * problems than it would solve. The date format must be changed + * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or + * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. + *

+ * @param serverLanguageCode The value to set to the serverLanguageCode property. + */ + public void setServerLanguageCode(String serverLanguageCode) { + this.serverLanguageCode = serverLanguageCode; + } + + /** + * Looks up the supplied language code in the internally maintained table of + * language codes. Returns a DateFormatSymbols object configured with + * short month names corresponding to the code. If there is no corresponding + * entry in the table, the object returned will be that for + * Locale.US + * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} + * @return a DateFormatSymbols object configured with short month names + * corresponding to the supplied code, or with month names for + * Locale.US if there is no corresponding entry in the internal + * table. + */ + public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) + { + Object lang = LANGUAGE_CODE_MAP.get(languageCode); + if (lang != null) { + if (lang instanceof Locale) { + return new DateFormatSymbols((Locale) lang); + } else if (lang instanceof String){ + return getDateFormatSymbols((String) lang); + } + } + return new DateFormatSymbols(Locale.US); + } + + /** + * Returns a DateFormatSymbols object configured with short month names + * as in the supplied string + * @param shortmonths This should be as described in + * {@link #setShortMonthNames(String) shortMonthNames} + * @return a DateFormatSymbols object configured with short month names + * as in the supplied string + */ + public static DateFormatSymbols getDateFormatSymbols(String shortmonths) + { + String[] months = splitShortMonthString(shortmonths); + DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); + dfs.setShortMonths(months); + return dfs; + } + + private static String[] splitShortMonthString(String shortmonths) { + StringTokenizer st = new StringTokenizer(shortmonths, "|"); + int monthcnt = st.countTokens(); + if (12 != monthcnt) { + throw new IllegalArgumentException( + "expecting a pipe-delimited string containing 12 tokens"); + } + String[] months = new String[13]; + int pos = 0; + while(st.hasMoreTokens()) { + months[pos++] = st.nextToken(); + } + months[pos]=""; + return months; + } + + /** + * Returns a Collection of all the language codes currently supported + * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} + * for a functional descrption of language codes within this system. + * + * @return a Collection of all the language codes currently supported + * by this class + */ + public static Collection getSupportedLanguageCodes() { + return LANGUAGE_CODE_MAP.keySet(); + } + + +} diff --git a/src/org/apache/commons/net/ftp/FTPCommand.java b/src/org/apache/commons/net/ftp/FTPCommand.java new file mode 100644 index 0000000..d016dff --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPCommand.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +/*** + * FTPCommand stores a set of constants for FTP command codes. To interpret + * the meaning of the codes, familiarity with RFC 959 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 959. For those who think in terms of the actual FTP commands, + * a set of constants such as {@link #USER USER } are provided + * where the constant name is the same as the FTP command. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FTPCommand +{ + + + public static final int USER = 0; + public static final int PASS = 1; + public static final int ACCT = 2; + public static final int CWD = 3; + public static final int CDUP = 4; + public static final int SMNT = 5; + public static final int REIN = 6; + public static final int QUIT = 7; + public static final int PORT = 8; + public static final int PASV = 9; + public static final int TYPE = 10; + public static final int STRU = 11; + public static final int MODE = 12; + public static final int RETR = 13; + public static final int STOR = 14; + public static final int STOU = 15; + public static final int APPE = 16; + public static final int ALLO = 17; + public static final int REST = 18; + public static final int RNFR = 19; + public static final int RNTO = 20; + public static final int ABOR = 21; + public static final int DELE = 22; + public static final int RMD = 23; + public static final int MKD = 24; + public static final int PWD = 25; + public static final int LIST = 26; + public static final int NLST = 27; + public static final int SITE = 28; + public static final int SYST = 29; + public static final int STAT = 30; + public static final int HELP = 31; + public static final int NOOP = 32; + /** @since 2.0 */ + public static final int MDTM = 33; + + public static final int USERNAME = USER; + public static final int PASSWORD = PASS; + public static final int ACCOUNT = ACCT; + public static final int CHANGE_WORKING_DIRECTORY = CWD; + public static final int CHANGE_TO_PARENT_DIRECTORY = CDUP; + public static final int STRUCTURE_MOUNT = SMNT; + public static final int REINITIALIZE = REIN; + public static final int LOGOUT = QUIT; + public static final int DATA_PORT = PORT; + public static final int PASSIVE = PASV; + public static final int REPRESENTATION_TYPE = TYPE; + public static final int FILE_STRUCTURE = STRU; + public static final int TRANSFER_MODE = MODE; + public static final int RETRIEVE = RETR; + public static final int STORE = STOR; + public static final int STORE_UNIQUE = STOU; + public static final int APPEND = APPE; + public static final int ALLOCATE = ALLO; + public static final int RESTART = REST; + public static final int RENAME_FROM = RNFR; + public static final int RENAME_TO = RNTO; + public static final int ABORT = ABOR; + public static final int DELETE = DELE; + public static final int REMOVE_DIRECTORY = RMD; + public static final int MAKE_DIRECTORY = MKD; + public static final int PRINT_WORKING_DIRECTORY = PWD; + // public static final int LIST = LIST; + public static final int NAME_LIST = NLST; + public static final int SITE_PARAMETERS = SITE; + public static final int SYSTEM = SYST; + public static final int STATUS = STAT; + //public static final int HELP = HELP; + //public static final int NOOP = NOOP; + /** @since 2.0 */ + public static final int MOD_TIME = MDTM; + + // Cannot be instantiated + private FTPCommand() + {} + + static final String[] _commands = { + "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", + "PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", + "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", + "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP" + }; + + /** + * Retrieve the FTP protocol command string corresponding to a specified + * command code. + *

+ * @param command The command code. + * @return The FTP protcol command string corresponding to a specified + * command code. + */ + public static final String getCommand(int command) + { + return _commands[command]; + } +} diff --git a/src/org/apache/commons/net/ftp/FTPConnectionClosedException.java b/src/org/apache/commons/net/ftp/FTPConnectionClosedException.java new file mode 100644 index 0000000..3eccbf4 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPConnectionClosedException.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.IOException; + +/*** + * FTPConnectionClosedException is used to indicate the premature or + * unexpected closing of an FTP connection resulting from a + * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } + * response (FTP reply code 421) to a + * failed FTP command. This exception is derived from IOException and + * therefore may be caught either as an IOException or specifically as an + * FTPConnectionClosedException. + *

+ *

+ * @author Daniel F. Savarese + * @see FTP + * @see FTPClient + ***/ + +public class FTPConnectionClosedException extends IOException +{ + + /*** Constructs a FTPConnectionClosedException with no message ***/ + public FTPConnectionClosedException() + { + super(); + } + + /*** + * Constructs a FTPConnectionClosedException with a specified message. + *

+ * @param message The message explaining the reason for the exception. + ***/ + public FTPConnectionClosedException(String message) + { + super(message); + } + +} diff --git a/src/org/apache/commons/net/ftp/FTPFile.java b/src/org/apache/commons/net/ftp/FTPFile.java new file mode 100644 index 0000000..dd67904 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPFile.java @@ -0,0 +1,392 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.Serializable; +import java.util.Calendar; + +/*** + * The FTPFile class is used to represent information about files stored + * on an FTP server. Because there is no standard representation for + * file information on FTP servers, it may not always be possible to + * extract all the information that can be represented by FTPFile, or + * it may even be possible to extract more information. In cases where + * more information can be extracted, you will want to subclass FTPFile + * and implement your own {@link org.apache.commons.net.ftp.FTPFileListParser} + * to extract the information. + * However, most FTP servers return file information in a format that + * can be completely parsed by + * {@link org.apache.commons.net.ftp.DefaultFTPFileListParser} + * and stored in FTPFile. + *

+ *

+ * @author Daniel F. Savarese + * @see FTPFileListParser + * @see DefaultFTPFileListParser + * @see FTPClient#listFiles + ***/ + +public class FTPFile implements Serializable +{ + /** A constant indicating an FTPFile is a file. ***/ + public static final int FILE_TYPE = 0; + /** A constant indicating an FTPFile is a directory. ***/ + public static final int DIRECTORY_TYPE = 1; + /** A constant indicating an FTPFile is a symbolic link. ***/ + public static final int SYMBOLIC_LINK_TYPE = 2; + /** A constant indicating an FTPFile is of unknown type. ***/ + public static final int UNKNOWN_TYPE = 3; + + /** A constant indicating user access permissions. ***/ + public static final int USER_ACCESS = 0; + /** A constant indicating group access permissions. ***/ + public static final int GROUP_ACCESS = 1; + /** A constant indicating world access permissions. ***/ + public static final int WORLD_ACCESS = 2; + + /** A constant indicating file/directory read permission. ***/ + public static final int READ_PERMISSION = 0; + /** A constant indicating file/directory write permission. ***/ + public static final int WRITE_PERMISSION = 1; + /** + * A constant indicating file execute permission or directory listing + * permission. + ***/ + public static final int EXECUTE_PERMISSION = 2; + + int _type, _hardLinkCount; + long _size; + String _rawListing, _user, _group, _name, _link; + Calendar _date; + boolean[] _permissions[]; + + /*** Creates an empty FTPFile. ***/ + public FTPFile() + { + _permissions = new boolean[3][3]; + _rawListing = null; + _type = UNKNOWN_TYPE; + _hardLinkCount = 0; + _size = 0; + _user = null; + _group = null; + _date = null; + _name = null; + } + + + /*** + * Set the original FTP server raw listing from which the FTPFile was + * created. + *

+ * @param rawListing The raw FTP server listing. + ***/ + public void setRawListing(String rawListing) + { + _rawListing = rawListing; + } + + /*** + * Get the original FTP server raw listing used to initialize the FTPFile. + *

+ * @return The original FTP server raw listing used to initialize the + * FTPFile. + ***/ + public String getRawListing() + { + return _rawListing; + } + + + /*** + * Determine if the file is a directory. + *

+ * @return True if the file is of type DIRECTORY_TYPE, false if + * not. + ***/ + public boolean isDirectory() + { + return (_type == DIRECTORY_TYPE); + } + + /*** + * Determine if the file is a regular file. + *

+ * @return True if the file is of type FILE_TYPE, false if + * not. + ***/ + public boolean isFile() + { + return (_type == FILE_TYPE); + } + + /*** + * Determine if the file is a symbolic link. + *

+ * @return True if the file is of type UNKNOWN_TYPE, false if + * not. + ***/ + public boolean isSymbolicLink() + { + return (_type == SYMBOLIC_LINK_TYPE); + } + + /*** + * Determine if the type of the file is unknown. + *

+ * @return True if the file is of type UNKNOWN_TYPE, false if + * not. + ***/ + public boolean isUnknown() + { + return (_type == UNKNOWN_TYPE); + } + + + /*** + * Set the type of the file (DIRECTORY_TYPE, + * FILE_TYPE, etc.). + *

+ * @param type The integer code representing the type of the file. + ***/ + public void setType(int type) + { + _type = type; + } + + + /*** + * Return the type of the file (one of the _TYPE constants), + * e.g., if it is a directory, a regular file, or a symbolic link. + *

+ * @return The type of the file. + ***/ + public int getType() + { + return _type; + } + + + /*** + * Set the name of the file. + *

+ * @param name The name of the file. + ***/ + public void setName(String name) + { + _name = name; + } + + /*** + * Return the name of the file. + *

+ * @return The name of the file. + ***/ + public String getName() + { + return _name; + } + + + /** + * Set the file size in bytes. + * @param size The file size in bytes. + */ + public void setSize(long size) + { + _size = size; + } + + + /*** + * Return the file size in bytes. + *

+ * @return The file size in bytes. + ***/ + public long getSize() + { + return _size; + } + + + /*** + * Set the number of hard links to this file. This is not to be + * confused with symbolic links. + *

+ * @param links The number of hard links to this file. + ***/ + public void setHardLinkCount(int links) + { + _hardLinkCount = links; + } + + + /*** + * Return the number of hard links to this file. This is not to be + * confused with symbolic links. + *

+ * @return The number of hard links to this file. + ***/ + public int getHardLinkCount() + { + return _hardLinkCount; + } + + + /*** + * Set the name of the group owning the file. This may be + * a string representation of the group number. + *

+ * @param group The name of the group owning the file. + ***/ + public void setGroup(String group) + { + _group = group; + } + + + /*** + * Returns the name of the group owning the file. Sometimes this will be + * a string representation of the group number. + *

+ * @return The name of the group owning the file. + ***/ + public String getGroup() + { + return _group; + } + + + /*** + * Set the name of the user owning the file. This may be + * a string representation of the user number; + *

+ * @param user The name of the user owning the file. + ***/ + public void setUser(String user) + { + _user = user; + } + + /*** + * Returns the name of the user owning the file. Sometimes this will be + * a string representation of the user number. + *

+ * @return The name of the user owning the file. + ***/ + public String getUser() + { + return _user; + } + + + /*** + * If the FTPFile is a symbolic link, use this method to set the name of the + * file being pointed to by the symbolic link. + *

+ * @param link The file pointed to by the symbolic link. + ***/ + public void setLink(String link) + { + _link = link; + } + + + /*** + * If the FTPFile is a symbolic link, this method returns the name of the + * file being pointed to by the symbolic link. Otherwise it returns null. + *

+ * @return The file pointed to by the symbolic link (null if the FTPFile + * is not a symbolic link). + ***/ + public String getLink() + { + return _link; + } + + + /*** + * Set the file timestamp. This usually the last modification time. + * The parameter is not cloned, so do not alter its value after calling + * this method. + *

+ * @param date A Calendar instance representing the file timestamp. + ***/ + public void setTimestamp(Calendar date) + { + _date = date; + } + + + /*** + * Returns the file timestamp. This usually the last modification time. + *

+ * @return A Calendar instance representing the file timestamp. + ***/ + public Calendar getTimestamp() + { + return _date; + } + + + /*** + * Set if the given access group (one of the _ACCESS + * constants) has the given access permission (one of the + * _PERMISSION constants) to the file. + *

+ * @param access The access group (one of the _ACCESS + * constants) + * @param permission The access permission (one of the + * _PERMISSION constants) + * @param value True if permission is allowed, false if not. + ***/ + public void setPermission(int access, int permission, boolean value) + { + _permissions[access][permission] = value; + } + + + /*** + * Determines if the given access group (one of the _ACCESS + * constants) has the given access permission (one of the + * _PERMISSION constants) to the file. + *

+ * @param access The access group (one of the _ACCESS + * constants) + * @param permission The access permission (one of the + * _PERMISSION constants) + ***/ + public boolean hasPermission(int access, int permission) + { + return _permissions[access][permission]; + } + + + /*** + * Returns a string representation of the FTPFile information. This + * will be the raw FTP server listing that was used to initialize the + * FTPFile instance. + *

+ * @return A string representation of the FTPFile information. + ***/ + @Override + public String toString() + { + return _rawListing; + } + +} diff --git a/src/org/apache/commons/net/ftp/FTPFileEntryParser.java b/src/org/apache/commons/net/ftp/FTPFileEntryParser.java new file mode 100644 index 0000000..8e6d09c --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPFileEntryParser.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; + +/** + * FTPFileEntryParser defines the interface for parsing a single FTP file + * listing and converting that information into an + * {@link org.apache.commons.net.ftp.FTPFile} instance. + * Sometimes you will want to parse unusual listing formats, in which + * case you would create your own implementation of FTPFileEntryParser and + * if necessary, subclass FTPFile. + *

+ * Here are some examples showing how to use one of the classes that + * implement this interface. + *

+ * The first example shows how to get an iterable list of files in which the + * more expensive FTPFile objects are not created until needed. This + * is suitable for paged displays. It requires that a parser object be created + * beforehand: parser is an object (in the package + * org.apache.commons.net.ftp.parser) + * implementing this inteface. + * + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFileList list = f.createFileList(directory, parser);
+ *    FTPFileIterator iter = list.iterator();
+ *
+ *    while (iter.hasNext()) {
+ *       FTPFile[] files = iter.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ * + * The second example uses the revised FTPClient.listFiles() + * API to pull the whole list from the subfolder subfolder in + * one call, attempting to automatically detect the parser type. This + * method, without a parserKey parameter, indicates that autodection should + * be used. + * + *
+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = f.listFiles("subfolder");
+ * 
+ * + * The third example uses the revised FTPClient.listFiles()> + * API to pull the whole list from the current working directory in one call, + * but specifying by classname the parser to be used. For this particular + * parser class, this approach is necessary since there is no way to + * autodetect this server type. + * + *
+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = f.listFiles(
+ *      "org.apache.commons.net.ftp.parser.EnterpriseUnixFTPFileEntryParser",
+ *      ".");
+ * 
+ * + * The fourth example uses the revised FTPClient.listFiles() + * API to pull a single file listing in an arbitrary directory in one call, + * specifying by KEY the parser to be used, in this case, VMS. + * + *
+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPFile[] files = f.listFiles("VMS", "subfolder/foo.java");
+ * 
+ * + * @author Steve Cohen + * @version $Id: FTPFileEntryParser.java 636854 2008-03-13 19:55:01Z sebb $ + * @see org.apache.commons.net.ftp.FTPFile + * @see org.apache.commons.net.ftp.FTPClient#createFileList + */ +public interface FTPFileEntryParser +{ + /** + * Parses a line of an FTP server file listing and converts it into a usable + * format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null should be + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param listEntry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + FTPFile parseFTPEntry(String listEntry); + + /** + * Reads the next entry using the supplied BufferedReader object up to + * whatever delemits one entry from the next. Implementors must define + * this for the particular ftp system being parsed. In many but not all + * cases, this can be defined simply by calling BufferedReader.readLine(). + * + * @param reader The BufferedReader object from which entries are to be + * read. + * + * @return A string representing the next ftp entry or null if none found. + * @exception IOException thrown on any IO Error reading from the reader. + */ + String readNextEntry(BufferedReader reader) throws IOException; + + + /** + * This method is a hook for those implementors (such as + * VMSVersioningFTPEntryParser, and possibly others) which need to + * perform some action upon the FTPFileList after it has been created + * from the server stream, but before any clients see the list. + * + * The default implementation can be a no-op. + * + * @param original Original list after it has been created from the server stream + * + * @return Original list as processed by this method. + */ + List preParse(List original); + + +} + + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java b/src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java new file mode 100644 index 0000000..22214fe --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +/** + * This abstract class implements both the older FTPFileListParser and + * newer FTPFileEntryParser interfaces with default functionality. + * All the classes in the parser subpackage inherit from this. + * + */ +public abstract class FTPFileEntryParserImpl + implements FTPFileEntryParser +{ + /** + * The constructor for a FTPFileEntryParserImpl object. + */ + public FTPFileEntryParserImpl() + { + } + + /** + * Reads the next entry using the supplied BufferedReader object up to + * whatever delemits one entry from the next. This default implementation + * simply calls BufferedReader.readLine(). + * + * @param reader The BufferedReader object from which entries are to be + * read. + * + * @return A string representing the next ftp entry or null if none found. + * @exception java.io.IOException thrown on any IO Error reading from the reader. + */ + public String readNextEntry(BufferedReader reader) throws IOException + { + return reader.readLine(); + } + /** + * This method is a hook for those implementors (such as + * VMSVersioningFTPEntryParser, and possibly others) which need to + * perform some action upon the FTPFileList after it has been created + * from the server stream, but before any clients see the list. + * + * This default implementation removes entries that do not parse as files. + * + * @param original Original list after it has been created from the server stream + * + * @return original unmodified. + */ + public List preParse(List original) { + Iterator it = original.iterator(); + while (it.hasNext()){ + String entry = it.next(); + if (null == parseFTPEntry(entry)) { + it.remove(); + } + } + return original; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/src/org/apache/commons/net/ftp/FTPListParseEngine.java b/src/org/apache/commons/net/ftp/FTPListParseEngine.java new file mode 100644 index 0000000..468bf39 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPListParseEngine.java @@ -0,0 +1,290 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + + +/** + * This class handles the entire process of parsing a listing of + * file entries from the server. + *

+ * This object defines a two-part parsing mechanism. + *

+ * The first part is comprised of reading the raw input into an internal + * list of strings. Every item in this list corresponds to an actual + * file. All extraneous matter emitted by the server will have been + * removed by the end of this phase. This is accomplished in conjunction + * with the FTPFileEntryParser associated with this engine, by calling + * its methods readNextEntry() - which handles the issue of + * what delimits one entry from another, usually but not always a line + * feed and preParse() - which handles removal of + * extraneous matter such as the preliminary lines of a listing, removal + * of duplicates on versioning systems, etc. + *

+ * The second part is composed of the actual parsing, again in conjunction + * with the particular parser used by this engine. This is controlled + * by an iterator over the internal list of strings. This may be done + * either in block mode, by calling the getNext() and + * getPrevious() methods to provide "paged" output of less + * than the whole list at one time, or by calling the + * getFiles() method to return the entire list. + *

+ * Examples: + *

+ * Paged access: + *

+ *    FTPClient f=FTPClient();
+ *    f.connect(server);
+ *    f.login(username, password);
+ *    FTPListParseEngine engine = f.initiateListParsing(directory);
+ *
+ *    while (engine.hasNext()) {
+ *       FTPFile[] files = engine.getNext(25);  // "page size" you want
+ *       //do whatever you want with these files, display them, etc.
+ *       //expensive FTPFile objects not created until needed.
+ *    }
+ * 
+ *

+ * For unpaged access, simply use FTPClient.listFiles(). That method + * uses this class transparently. + * @version $Id: FTPListParseEngine.java 658518 2008-05-21 01:04:30Z sebb $ + */ +public class FTPListParseEngine { + private List entries = new LinkedList(); + private ListIterator _internalIterator = entries.listIterator(); + + FTPFileEntryParser parser = null; + + public FTPListParseEngine(FTPFileEntryParser parser) { + this.parser = parser; + } + + /** + * handle the iniitial reading and preparsing of the list returned by + * the server. After this method has completed, this object will contain + * a list of unparsed entries (Strings) each referring to a unique file + * on the server. + * + * @param stream input stream provided by the server socket. + * + * @exception IOException + * thrown on any failure to read from the sever. + */ + public void readServerList(InputStream stream, String encoding) + throws IOException + { + this.entries = new LinkedList(); + readStream(stream, encoding); + this.parser.preParse(this.entries); + resetIterator(); + } + + /** + * handle the iniitial reading and preparsing of the list returned by + * the server. After this method has completed, this object will contain + * a list of unparsed entries (Strings) each referring to a unique file + * on the server. + * + * @param stream input stream provided by the server socket. + * + * @exception IOException + * thrown on any failure to read from the sever. + * + * @deprecated The version of this method which takes an encoding should be used. + */ + public void readServerList(InputStream stream) + throws IOException + { + readServerList(stream, null); + } + + + + /** + * Internal method for reading the input into the entries list. + * After this method has completed, entries will contain a + * collection of entries (as defined by + * FTPFileEntryParser.readNextEntry()), but this may contain + * various non-entry preliminary lines from the server output, duplicates, + * and other data that will not be part of the final listing. + * + * @param stream The socket stream on which the input will be read. + * @param encoding The encoding to use. + * + * @exception IOException + * thrown on any failure to read the stream + */ + private void readStream(InputStream stream, String encoding) throws IOException + { + BufferedReader reader; + if (encoding == null) + { + reader = new BufferedReader(new InputStreamReader(stream)); + } + else + { + reader = new BufferedReader(new InputStreamReader(stream, encoding)); + } + + String line = this.parser.readNextEntry(reader); + + while (line != null) + { + this.entries.add(line); + line = this.parser.readNextEntry(reader); + } + reader.close(); + } + + /** + * Returns an array of at most quantityRequested FTPFile + * objects starting at this object's internal iterator's current position. + * If fewer than quantityRequested such + * elements are available, the returned array will have a length equal + * to the number of entries at and after after the current position. + * If no such entries are found, this array will have a length of 0. + * + * After this method is called this object's internal iterator is advanced + * by a number of positions equal to the size of the array returned. + * + * @param quantityRequested + * the maximum number of entries we want to get. + * + * @return an array of at most quantityRequested FTPFile + * objects starting at the current position of this iterator within its + * list and at least the number of elements which exist in the list at + * and after its current position. + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + */ + public FTPFile[] getNext(int quantityRequested) { + List tmpResults = new LinkedList(); + int count = quantityRequested; + while (count > 0 && this._internalIterator.hasNext()) { + String entry = this._internalIterator.next(); + FTPFile temp = this.parser.parseFTPEntry(entry); + tmpResults.add(temp); + count--; + } + return tmpResults.toArray(new FTPFile[0]); + + } + + /** + * Returns an array of at most quantityRequested FTPFile + * objects starting at this object's internal iterator's current position, + * and working back toward the beginning. + * + * If fewer than quantityRequested such + * elements are available, the returned array will have a length equal + * to the number of entries at and after after the current position. + * If no such entries are found, this array will have a length of 0. + * + * After this method is called this object's internal iterator is moved + * back by a number of positions equal to the size of the array returned. + * + * @param quantityRequested + * the maximum number of entries we want to get. + * + * @return an array of at most quantityRequested FTPFile + * objects starting at the current position of this iterator within its + * list and at least the number of elements which exist in the list at + * and after its current position. This array will be in the same order + * as the underlying list (not reversed). + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + */ + public FTPFile[] getPrevious(int quantityRequested) { + List tmpResults = new LinkedList(); + int count = quantityRequested; + while (count > 0 && this._internalIterator.hasPrevious()) { + String entry = this._internalIterator.previous(); + FTPFile temp = this.parser.parseFTPEntry(entry); + tmpResults.add(0,temp); + count--; + } + return tmpResults.toArray(new FTPFile[0]); + } + + /** + * Returns an array of FTPFile objects containing the whole list of + * files returned by the server as read by this object's parser. + * + * @return an array of FTPFile objects containing the whole list of + * files returned by the server as read by this object's parser. + *

+ * NOTE: This array may contain null members if any of the + * individual file listings failed to parse. The caller should + * check each entry for null before referencing it. + * @exception IOException + */ + public FTPFile[] getFiles() + throws IOException + { + List tmpResults = new LinkedList(); + Iterator iter = this.entries.iterator(); + while (iter.hasNext()) { + String entry = iter.next(); + FTPFile temp = this.parser.parseFTPEntry(entry); + tmpResults.add(temp); + } + return tmpResults.toArray(new FTPFile[0]); + + } + + /** + * convenience method to allow clients to know whether this object's + * internal iterator's current position is at the end of the list. + * + * @return true if internal iterator is not at end of list, false + * otherwise. + */ + public boolean hasNext() { + return _internalIterator.hasNext(); + } + + /** + * convenience method to allow clients to know whether this object's + * internal iterator's current position is at the beginning of the list. + * + * @return true if internal iterator is not at beginning of list, false + * otherwise. + */ + public boolean hasPrevious() { + return _internalIterator.hasPrevious(); + } + + /** + * resets this object's internal iterator to the beginning of the list. + */ + public void resetIterator() { + this._internalIterator = this.entries.listIterator(); + } +} diff --git a/src/org/apache/commons/net/ftp/FTPReply.java b/src/org/apache/commons/net/ftp/FTPReply.java new file mode 100644 index 0000000..6386568 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPReply.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +/*** + * FTPReply stores a set of constants for FTP reply codes. To interpret + * the meaning of the codes, familiarity with RFC 959 is assumed. + * The mnemonic constant names are transcriptions from the code descriptions + * of RFC 959. For those who think in terms of the actual reply code values, + * a set of CODE_NUM constants are provided where NUM is the numerical value + * of the code. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FTPReply +{ + + public static final int CODE_110 = 110; + public static final int CODE_120 = 120; + public static final int CODE_125 = 125; + public static final int CODE_150 = 150; + public static final int CODE_200 = 200; + public static final int CODE_202 = 202; + public static final int CODE_211 = 211; + public static final int CODE_212 = 212; + public static final int CODE_213 = 213; + public static final int CODE_214 = 214; + public static final int CODE_215 = 215; + public static final int CODE_220 = 220; + public static final int CODE_221 = 221; + public static final int CODE_225 = 225; + public static final int CODE_226 = 226; + public static final int CODE_227 = 227; + public static final int CODE_230 = 230; + public static final int CODE_250 = 250; + public static final int CODE_257 = 257; + public static final int CODE_331 = 331; + public static final int CODE_332 = 332; + public static final int CODE_350 = 350; + public static final int CODE_421 = 421; + public static final int CODE_425 = 425; + public static final int CODE_426 = 426; + public static final int CODE_450 = 450; + public static final int CODE_451 = 451; + public static final int CODE_452 = 452; + public static final int CODE_500 = 500; + public static final int CODE_501 = 501; + public static final int CODE_502 = 502; + public static final int CODE_503 = 503; + public static final int CODE_504 = 504; + public static final int CODE_521 = 521; + public static final int CODE_530 = 530; + public static final int CODE_532 = 532; + public static final int CODE_550 = 550; + public static final int CODE_551 = 551; + public static final int CODE_552 = 552; + public static final int CODE_553 = 553; + + public static final int RESTART_MARKER = CODE_110; + public static final int SERVICE_NOT_READY = CODE_120; + public static final int DATA_CONNECTION_ALREADY_OPEN = CODE_125; + public static final int FILE_STATUS_OK = CODE_150; + public static final int COMMAND_OK = CODE_200; + public static final int COMMAND_IS_SUPERFLUOUS = CODE_202; + public static final int SYSTEM_STATUS = CODE_211; + public static final int DIRECTORY_STATUS = CODE_212; + public static final int FILE_STATUS = CODE_213; + public static final int HELP_MESSAGE = CODE_214; + public static final int NAME_SYSTEM_TYPE = CODE_215; + public static final int SERVICE_READY = CODE_220; + public static final int SERVICE_CLOSING_CONTROL_CONNECTION = CODE_221; + public static final int DATA_CONNECTION_OPEN = CODE_225; + public static final int CLOSING_DATA_CONNECTION = CODE_226; + public static final int ENTERING_PASSIVE_MODE = CODE_227; + public static final int USER_LOGGED_IN = CODE_230; + public static final int FILE_ACTION_OK = CODE_250; + public static final int PATHNAME_CREATED = CODE_257; + public static final int NEED_PASSWORD = CODE_331; + public static final int NEED_ACCOUNT = CODE_332; + public static final int FILE_ACTION_PENDING = CODE_350; + public static final int SERVICE_NOT_AVAILABLE = CODE_421; + public static final int CANNOT_OPEN_DATA_CONNECTION = CODE_425; + public static final int TRANSFER_ABORTED = CODE_426; + public static final int FILE_ACTION_NOT_TAKEN = CODE_450; + public static final int ACTION_ABORTED = CODE_451; + public static final int INSUFFICIENT_STORAGE = CODE_452; + public static final int UNRECOGNIZED_COMMAND = CODE_500; + public static final int SYNTAX_ERROR_IN_ARGUMENTS = CODE_501; + public static final int COMMAND_NOT_IMPLEMENTED = CODE_502; + public static final int BAD_COMMAND_SEQUENCE = CODE_503; + public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = CODE_504; + public static final int NOT_LOGGED_IN = CODE_530; + public static final int NEED_ACCOUNT_FOR_STORING_FILES = CODE_532; + public static final int FILE_UNAVAILABLE = CODE_550; + public static final int PAGE_TYPE_UNKNOWN = CODE_551; + public static final int STORAGE_ALLOCATION_EXCEEDED = CODE_552; + public static final int FILE_NAME_NOT_ALLOWED = CODE_553; + + // FTPS Reply Codes + /** @since 2.0 */ + public static final int CODE_234 = 234; + /** @since 2.0 */ + public static final int CODE_235 = 235; + /** @since 2.0 */ + public static final int CODE_334 = 334; + /** @since 2.0 */ + public static final int CODE_335 = 335; + /** @since 2.0 */ + public static final int CODE_431 = 431; + /** @since 2.0 */ + public static final int CODE_533 = 533; + /** @since 2.0 */ + public static final int CODE_534 = 534; + /** @since 2.0 */ + public static final int CODE_535 = 535; + /** @since 2.0 */ + public static final int CODE_536 = 536; + + /** @since 2.0 */ + public static final int SECURITY_DATA_EXCHANGE_COMPLETE = CODE_234; + /** @since 2.0 */ + public static final int SECURITY_DATA_EXCHANGE_SUCCESSFULLY = CODE_235; + /** @since 2.0 */ + public static final int SECURITY_MECHANISM_IS_OK = CODE_334; + /** @since 2.0 */ + public static final int SECURITY_DATA_IS_ACCEPTABLE = CODE_335; + /** @since 2.0 */ + public static final int UNAVAILABLE_RESOURCE = CODE_431; + /** @since 2.0 */ + public static final int DENIED_FOR_POLICY_REASONS = CODE_533; + /** @since 2.0 */ + public static final int REQUEST_DENIED = CODE_534; + /** @since 2.0 */ + public static final int FAILED_SECURITY_CHECK = CODE_535; + /** @since 2.0 */ + public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = CODE_536; + + + // Cannot be instantiated + private FTPReply() + {} + + /*** + * Determine if a reply code is a positive preliminary response. All + * codes beginning with a 1 are positive preliminary responses. + * Postitive preliminary responses are used to indicate tentative success. + * No further commands can be issued to the FTP server after a positive + * preliminary response until a follow up response is received from the + * server. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive preliminary response, false + * if not. + ***/ + public static boolean isPositivePreliminary(int reply) + { + return (reply >= 100 && reply < 200); + } + + /*** + * Determine if a reply code is a positive completion response. All + * codes beginning with a 2 are positive completion responses. + * The FTP server will send a positive completion response on the final + * successful completion of a command. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive completion response, false + * if not. + ***/ + public static boolean isPositiveCompletion(int reply) + { + return (reply >= 200 && reply < 300); + } + + /*** + * Determine if a reply code is a positive intermediate response. All + * codes beginning with a 3 are positive intermediate responses. + * The FTP server will send a positive intermediate response on the + * successful completion of one part of a multi-part sequence of + * commands. For example, after a successful USER command, a positive + * intermediate response will be sent to indicate that the server is + * ready for the PASS command. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a postive intermediate response, false + * if not. + ***/ + public static boolean isPositiveIntermediate(int reply) + { + return (reply >= 300 && reply < 400); + } + + /*** + * Determine if a reply code is a negative transient response. All + * codes beginning with a 4 are negative transient responses. + * The FTP server will send a negative transient response on the + * failure of a command that can be reattempted with success. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative transient response, false + * if not. + ***/ + public static boolean isNegativeTransient(int reply) + { + return (reply >= 400 && reply < 500); + } + + /*** + * Determine if a reply code is a negative permanent response. All + * codes beginning with a 5 are negative permanent responses. + * The FTP server will send a negative permanent response on the + * failure of a command that cannot be reattempted with success. + *

+ * @param reply The reply code to test. + * @return True if a reply code is a negative permanent response, false + * if not. + ***/ + public static boolean isNegativePermanent(int reply) + { + return (reply >= 500 && reply < 600); + } + +} diff --git a/src/org/apache/commons/net/ftp/FTPSClient.java b/src/org/apache/commons/net/ftp/FTPSClient.java new file mode 100644 index 0000000..f809c41 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPSClient.java @@ -0,0 +1,533 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +/** + * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to + * see wire-level SSL details. + * + * @version $Id: FTPSClient.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 2.0 + */ +public class FTPSClient extends FTPClient { + + /** keystore algorithm name. */ + public static String KEYSTORE_ALGORITHM; + /** truststore algorithm name. */ + public static String TRUSTSTORE_ALGORITHM; + /** provider name. */ + public static String PROVIDER; + /** truststore type. */ + public static String STORE_TYPE; + + /** The value that I can set in PROT command */ + private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; + /** Default PROT Command */ + private static final String DEFAULT_PROT = "C"; + /** Default protocol name */ + private static final String DEFAULT_PROTOCOL = "TLS"; + + /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ + private boolean isImplicit; + /** The use SSL/TLS protocol. */ + private String protocol = DEFAULT_PROTOCOL; + /** The AUTH Command value */ + private String auth = DEFAULT_PROTOCOL; + /** The context object. */ + private SSLContext context; + /** The socket object. */ + private Socket planeSocket; + /** The established socket flag. */ + private boolean isCreation = true; + /** The use client mode flag. */ + private boolean isClientMode = true; + /** The need client auth flag. */ + private boolean isNeedClientAuth = false; + /** The want client auth flag. */ + private boolean isWantClientAuth = false; + /** The cipher suites */ + private String[] suites = null; + /** The protocol versions */ + private String[] protocols = null; + + /** The FTPS {@link TrustManager} implementation. */ + private TrustManager trustManager = new FTPSTrustManager(); + + /** The {@link KeyManager} */ + private KeyManager keyManager; + + /** + * Constructor for FTPSClient. + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient() throws NoSuchAlgorithmException { + this.protocol = DEFAULT_PROTOCOL; + this.isImplicit = false; + } + + /** + * Constructor for FTPSClient. + * @param isImplicit The secutiry mode(Implicit/Explicit). + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient(boolean isImplicit) throws NoSuchAlgorithmException { + this.protocol = DEFAULT_PROTOCOL; + this.isImplicit = isImplicit; + } + + /** + * Constructor for FTPSClient. + * @param protocol the protocol + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient(String protocol) throws NoSuchAlgorithmException { + this.protocol = protocol; + this.isImplicit = false; + } + + /** + * Constructor for FTPSClient. + * @param protocol the protocol + * @param isImplicit The secutiry mode(Implicit/Explicit). + * @throws NoSuchAlgorithmException A requested cryptographic algorithm + * is not available in the environment. + */ + public FTPSClient(String protocol, boolean isImplicit) + throws NoSuchAlgorithmException { + this.protocol = protocol; + this.isImplicit = isImplicit; + } + + + /** + * Set AUTH command use value. + * This processing is done before connected processing. + * @param auth AUTH command use value. + */ + public void setAuthValue(String auth) { + this.auth = auth; + } + + /** + * Return AUTH command use value. + * @return AUTH command use value. + */ + public String getAuthValue() { + return this.auth; + } + + + /** + * Because there are so many connect() methods, + * the _connectAction_() method is provided as a means of performing + * some action immediately after establishing a connection, + * rather than reimplementing all of the connect() methods. + * @throws IOException If it throw by _connectAction_. + * @see org.apache.commons.net.SocketClient#_connectAction_() + */ + @Override + protected void _connectAction_() throws IOException { + // Implicit mode. + if (isImplicit) sslNegotiation(); + super._connectAction_(); + // Explicit mode. + if (!isImplicit) { + execAUTH(); + sslNegotiation(); + } + } + + /** + * AUTH command. + * @throws SSLException If it server reply code not equal "234" and "334". + * @throws IOException If an I/O error occurs while either sending + * the command. + */ + private void execAUTH() throws SSLException, IOException { + int replyCode = sendCommand( + FTPSCommand._commands[FTPSCommand.AUTH], auth); + if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { + // replyCode = 334 + // I carry out an ADAT command. + } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { + throw new SSLException(getReplyString()); + } + } + + /** + * Performs a lazy init of the SSL context + * @throws IOException + */ + private void initSslContext() throws IOException { + if(context == null) { + try { + context = SSLContext.getInstance(protocol); + + context.init(new KeyManager[] { getKeyManager() } , new TrustManager[] { getTrustManager() } , null); + } catch (KeyManagementException e) { + IOException ioe = new IOException("Could not initialize SSL context"); + ioe.initCause(e); + throw ioe; + } catch (NoSuchAlgorithmException e) { + IOException ioe = new IOException("Could not initialize SSL context"); + ioe.initCause(e); + throw ioe; + } + } + } + + /** + * SSL/TLS negotiation. Acquires an SSL socket of a control + * connection and carries out handshake processing. + * @throws IOException A handicap breaks out by sever negotiation. + */ + private void sslNegotiation() throws IOException { + // Evacuation not ssl socket. + planeSocket = _socket_; + + initSslContext(); + + SSLSocketFactory ssf = context.getSocketFactory(); + String ip = _socket_.getInetAddress().getHostAddress(); + int port = _socket_.getPort(); + SSLSocket socket = + (SSLSocket) ssf.createSocket(_socket_, ip, port, true); + socket.setEnableSessionCreation(isCreation); + socket.setUseClientMode(isClientMode); + // server mode + if (!isClientMode) { + socket.setNeedClientAuth(isNeedClientAuth); + socket.setWantClientAuth(isWantClientAuth); + } + if (protocols != null) socket.setEnabledProtocols(protocols); + if (suites != null) socket.setEnabledCipherSuites(suites); + + socket.startHandshake(); + + _socket_ = socket; + _controlInput_ = new BufferedReader(new InputStreamReader( + socket .getInputStream(), getControlEncoding())); + _controlOutput_ = new BufferedWriter(new OutputStreamWriter( + socket.getOutputStream(), getControlEncoding())); + } + + /** + * Get the {@link KeyManager} instance. + * @return The {@link KeyManager} instance + */ + private KeyManager getKeyManager() { + return keyManager; + } + + /** + * Set a {@link KeyManager} to use + * + * @param keyManager The KeyManager implementation to set. + */ + public void setKeyManager(KeyManager keyManager) { + this.keyManager = keyManager; + } + + /** + * Controls whether new a SSL session may be established by this socket. + * @param isCreation The established socket flag. + */ + public void setEnabledSessionCreation(boolean isCreation) { + this.isCreation = isCreation; + } + + /** + * Returns true if new SSL sessions may be established by this socket. + * When a socket does not have a ssl socket, This return False. + * @return true - Indicates that sessions may be created; + * this is the default. + * false - indicates that an existing session must be resumed. + */ + public boolean getEnableSessionCreation() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getEnableSessionCreation(); + return false; + } + + /** + * Configures the socket to require client authentication. + * @param isNeedClientAuth The need client auth flag. + */ + public void setNeedClientAuth(boolean isNeedClientAuth) { + this.isNeedClientAuth = isNeedClientAuth; + } + + /** + * Returns true if the socket will require client authentication. + * When a socket does not have a ssl socket, This return False. + * @return true - If the server mode socket should request + * that the client authenticate itself. + */ + public boolean getNeedClientAuth() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getNeedClientAuth(); + return false; + } + + /** + * Configures the socket to request client authentication, + * but only if such a request is appropriate to the cipher + * suite negotiated. + * @param isWantClientAuth The want client auth flag. + */ + public void setWantClientAuth(boolean isWantClientAuth) { + this.isWantClientAuth = isWantClientAuth; + } + + /** + * Returns true if the socket will request client authentication. + * When a socket does not have a ssl socket, This return False. + * @return true - If the server mode socket should request + * that the client authenticate itself. + */ + public boolean getWantClientAuth() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getWantClientAuth(); + return false; + } + + /** + * Configures the socket to use client (or server) mode in its first + * handshake. + * @param isClientMode The use client mode flag. + */ + public void setUseClientMode(boolean isClientMode) { + this.isClientMode = isClientMode; + } + + /** + * Returns true if the socket is set to use client mode + * in its first handshake. + * When a socket does not have a ssl socket, This return False. + * @return true - If the socket should start its first handshake + * in "client" mode. + */ + public boolean getUseClientMode() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getUseClientMode(); + return false; + } + + /** + * Controls which particular cipher suites are enabled for use on this + * connection. I perform setting before a server negotiation. + * @param cipherSuites The cipher suites. + */ + public void setEnabledCipherSuites(String[] cipherSuites) { + suites = new String[cipherSuites.length]; + System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); + } + + /** + * Returns the names of the cipher suites which could be enabled + * for use on this connection. + * When a socket does not have a ssl socket, This return null. + * @return An array of cipher suite names. + */ + public String[] getEnabledCipherSuites() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getEnabledCipherSuites(); + return null; + } + + /** + * Controls which particular protocol versions are enabled for use on this + * connection. I perform setting before a server negotiation. + * @param protocolVersions The protocol versions. + */ + public void setEnabledProtocols(String[] protocolVersions) { + protocols = new String[protocolVersions.length]; + System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); + } + + /** + * Returns the names of the protocol versions which are currently + * enabled for use on this connection. + * When a socket does not have a ssl socket, This return null. + * @return An array of protocols. + */ + public String[] getEnabledProtocols() { + if (_socket_ instanceof SSLSocket) + return ((SSLSocket)_socket_).getEnabledProtocols(); + return null; + } + + /** + * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. + * @param pbsz Protection Buffer Size. + * @throws SSLException If it server reply code not equal "200". + * @throws IOException If an I/O error occurs while either sending + * the command. + */ + public void execPBSZ(long pbsz) throws SSLException, IOException { + if (pbsz < 0 || 4294967295L < pbsz) + throw new IllegalArgumentException(); + if (FTPReply.COMMAND_OK != sendCommand( + FTPSCommand._commands[FTPSCommand.PBSZ],String.valueOf(pbsz))) + throw new SSLException(getReplyString()); + } + + /** + * PROT command.
+ * C - Clear
+ * S - Safe(SSL protocol only)
+ * E - Confidential(SSL protocol only)
+ * P - Private + * @param prot Data Channel Protection Level. + * @throws SSLException If it server reply code not equal "200". + * @throws IOException If an I/O error occurs while either sending + * the command. + */ + public void execPROT(String prot) throws SSLException, IOException { + if (prot == null) prot = DEFAULT_PROT; + if (!checkPROTValue(prot)) throw new IllegalArgumentException(); + if (FTPReply.COMMAND_OK != sendCommand( + FTPSCommand._commands[FTPSCommand.PROT], prot)) + throw new SSLException(getReplyString()); + if (DEFAULT_PROT.equals(prot)) { + setSocketFactory(null); + setServerSocketFactory(null); + } else { + setSocketFactory(new FTPSSocketFactory(context)); + + initSslContext(); + + SSLServerSocketFactory ssf = context.getServerSocketFactory(); + + setServerSocketFactory(ssf); + } + } + + /** + * I check the value that I can set in PROT Command value. + * @param prot Data Channel Protection Level. + * @return True - A set point is right / False - A set point is not right + */ + private boolean checkPROTValue(String prot) { + for (int p = 0; p < PROT_COMMAND_VALUE.length; p++) { + if (PROT_COMMAND_VALUE[p].equals(prot)) return true; + } + return false; + } + + /** + * I carry out an ftp command. + * When a CCC command was carried out, I steep socket and SocketFactory + * in a state of not ssl. + * @parm command ftp command. + * @return server reply. + * @throws IOException If an I/O error occurs while either sending + * the command. + * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) + */ + @Override + public int sendCommand(String command, String args) throws IOException { + int repCode = super.sendCommand(command, args); + if (FTPSCommand._commands[FTPSCommand.CCC].equals(command)) { + if (FTPReply.COMMAND_OK == repCode) { + // TODO Check this - is this necessary at all? + _socket_ = planeSocket; + setSocketFactory(null); + } else { + throw new SSLException(getReplyString()); + } + } + return repCode; + } + + /** + * Returns a socket of the data connection. + * Wrapped as an {@link SSLSocket}, which carries out handshake processing. + * @pram command The text representation of the FTP command to send. + * @param arg The arguments to the FTP command. + * If this parameter is set to null, then the command is sent with + * no argument. + * @return A Socket corresponding to the established data connection. + * Null is returned if an FTP protocol error is reported at any point + * during the establishment and initialization of the connection. + * @throws IOException If there is any problem with the connection. + * @see org.apache.commons.net.ftp.FTPClient#_openDataConnection_(java.lang.String, int) + */ + @Override + protected Socket _openDataConnection_(int command, String arg) + throws IOException { + Socket socket = super._openDataConnection_(command, arg); + if (socket != null && socket instanceof SSLSocket) { + SSLSocket sslSocket = (SSLSocket)socket; + sslSocket.setUseClientMode(isClientMode); + sslSocket.setEnableSessionCreation(isCreation); + // server mode + if (!isClientMode) { + sslSocket.setNeedClientAuth(isNeedClientAuth); + sslSocket.setWantClientAuth(isWantClientAuth); + } + if (suites != null) + sslSocket.setEnabledCipherSuites(suites); + if (protocols != null) + sslSocket.setEnabledProtocols(protocols); + sslSocket.startHandshake(); + } + return socket; + } + + /** + * Get the currently configured {@link TrustManager}. + * + * @return A TrustManager instance. + */ + public TrustManager getTrustManager() { + return trustManager; + } + + /** + * Override the default {@link TrustManager} to use. + * + * @param trustManager The TrustManager implementation to set. + */ + public void setTrustManager(TrustManager trustManager) { + this.trustManager = trustManager; + } + + + +} diff --git a/src/org/apache/commons/net/ftp/FTPSCommand.java b/src/org/apache/commons/net/ftp/FTPSCommand.java new file mode 100644 index 0000000..6fd2efa --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPSCommand.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +/** + * I acquire a command added in FTPS. + * @since 2.0 + */ +public final class FTPSCommand { + public static final int AUTH = 0; + public static final int ADAT = 1; + public static final int PBSZ = 2; + public static final int PROT = 3; + public static final int CCC = 4; + + public static final int AUTHENTICATION_SECURITY_MECHANISM = AUTH; + public static final int AUTHENTICATION_SECURITY_DATA = ADAT; + public static final int PROTECTION_BUFFER_SIZE = PBSZ; + public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; + public static final int CLEAR_COMMAND_CHANNEL = CCC; + + static final String[] _commands = {"AUTH","ADAT","PBSZ","PROT","CCC"}; + + /** + * Retrieve the FTPS command string corresponding to a specified + * command code. + *

+ * @param command The command code. + * @return The FTPS command string corresponding to a specified + * command code. + */ + public static final String getCommand(int command) { + return _commands[command]; + } +} diff --git a/src/org/apache/commons/net/ftp/FTPSSocketFactory.java b/src/org/apache/commons/net/ftp/FTPSSocketFactory.java new file mode 100644 index 0000000..b7e1186 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPSSocketFactory.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.net.ftp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; + + +/** + * + * Implementation of org.apache.commons.net.SocketFactory + * + * @since 2.0 + */ +public class FTPSSocketFactory extends SocketFactory { + + private SSLContext context; + + public FTPSSocketFactory(SSLContext context) { + this.context = context; + } + + @Override + public Socket createSocket(String address, int port) throws UnknownHostException, IOException { + return this.context.getSocketFactory().createSocket(address, port); + } + + @Override + public Socket createSocket(InetAddress address, int port) throws IOException { + return this.context.getSocketFactory().createSocket(address, port); + } + + @Override + public Socket createSocket(String address, int port, InetAddress localAddress, int localPort) throws UnknownHostException, IOException { + return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); + } + + public ServerSocket createServerSocket(int port) throws IOException { + return this.init(this.context.getServerSocketFactory().createServerSocket(port)); + } + + public ServerSocket createServerSocket(int port, int backlog) throws IOException { + return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); + } + + public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { + return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); + } + + public ServerSocket init(ServerSocket socket) throws IOException { + ((SSLServerSocket) socket).setUseClientMode(true); + return socket; + } +} diff --git a/src/org/apache/commons/net/ftp/FTPSTrustManager.java b/src/org/apache/commons/net/ftp/FTPSTrustManager.java new file mode 100644 index 0000000..d1a2dd7 --- /dev/null +++ b/src/org/apache/commons/net/ftp/FTPSTrustManager.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * Custom {@link TrustManager} implementation. + * + * @version $Id: FTPSTrustManager.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 2.0 + */ +public class FTPSTrustManager implements X509TrustManager +{ + /** + * No-op + */ + public void checkClientTrusted(X509Certificate[] certificates, String authType) + { + return; + } + + public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException + { + for (int i = 0; i < certificates.length; ++i) + { + certificates[i].checkValidity(); + } + } + + public X509Certificate[] getAcceptedIssuers() + { + return null; + } +} diff --git a/src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java b/src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java new file mode 100644 index 0000000..4977b3f --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPFileEntryParser; +import org.apache.commons.net.ftp.FTPFileEntryParserImpl; + +/** + * This implementation allows to pack some FileEntryParsers together + * and handle the case where to returned dirstyle isnt clearly defined. + * The matching parser will be cached. + * If the cached parser wont match due to the server changed the dirstyle, + * a new matching parser will be searched. + * + * @author Mario Ivankovits + */ +public class CompositeFileEntryParser extends FTPFileEntryParserImpl +{ + private final FTPFileEntryParser[] ftpFileEntryParsers; + private FTPFileEntryParser cachedFtpFileEntryParser; + + public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) + { + super(); + + this.cachedFtpFileEntryParser = null; + this.ftpFileEntryParsers = ftpFileEntryParsers; + } + + public FTPFile parseFTPEntry(String listEntry) + { + if (cachedFtpFileEntryParser != null) + { + FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); + if (matched != null) + { + return matched; + } + } + else + { + for (int iterParser=0; iterParser < ftpFileEntryParsers.length; iterParser++) + { + FTPFileEntryParser ftpFileEntryParser = ftpFileEntryParsers[iterParser]; + + FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); + if (matched != null) + { + cachedFtpFileEntryParser = ftpFileEntryParser; + return matched; + } + } + } + return null; + } +} diff --git a/src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java b/src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java new file mode 100644 index 0000000..a3e832f --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; +import java.util.Calendar; + +import org.apache.commons.net.ftp.Configurable; +import org.apache.commons.net.ftp.FTPClientConfig; + + +/** + *

+ * This abstract class implements the common timestamp parsing + * algorithm for all the concrete parsers. Classes derived from + * this one will parse file listings via a supplied regular expression + * that pulls out the date portion as a separate string which is + * passed to the underlying {@link FTPTimestampParser delegate} to + * handle parsing of the file timestamp. + *

+ * This class also implements the {@link Configurable Configurable} + * interface to allow the parser to be configured from the outside. + *

+ * @since 1.4 + */ +/** + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Style - Code Templates - Comments + */ +public abstract class ConfigurableFTPFileEntryParserImpl +extends RegexFTPFileEntryParserImpl +implements Configurable +{ + + private FTPTimestampParser timestampParser; + + /** + * Only constructor for this absract class. + * @param regex Regular expression used main parsing of the + * file listing. + */ + public ConfigurableFTPFileEntryParserImpl(String regex) + { + super(regex); + this.timestampParser = new FTPTimestampParserImpl(); + } + + /** + * This method is called by the concrete parsers to delegate + * timestamp parsing to the timestamp parser. + *

+ * @param timestampStr the timestamp string pulled from the + * file listing by the regular expression parser, to be submitted + * to the timestampParser for extracting the timestamp. + * @return a java.util.Calendar containing results of the + * timestamp parse. + */ + public Calendar parseTimestamp(String timestampStr) throws ParseException { + return this.timestampParser.parseTimestamp(timestampStr); + } + + + /** + * Implementation of the {@link Configurable Configurable} + * interface. Configures this parser by delegating to the + * underlying Configurable FTPTimestampParser implementation, ' + * passing it the supplied {@link FTPClientConfig FTPClientConfig} + * if that is non-null or a default configuration defined by + * each concrete subclass. + *

+ * @param config the configuration to be used to configure this parser. + * If it is null, a default configuration defined by + * each concrete subclass is used instead. + */ + public void configure(FTPClientConfig config) + { + if (this.timestampParser instanceof Configurable) { + FTPClientConfig defaultCfg = getDefaultConfiguration(); + if (config != null) { + if (null == config.getDefaultDateFormatStr()) { + config.setDefaultDateFormatStr(defaultCfg.getDefaultDateFormatStr()); + } + if (null == config.getRecentDateFormatStr()) { + config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); + } + ((Configurable)this.timestampParser).configure(config); + } else { + ((Configurable)this.timestampParser).configure(defaultCfg); + } + } + } + + /** + * Each concrete subclass must define this member to create + * a default configuration to be used when that subclass is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for the subclass. + */ + protected abstract FTPClientConfig getDefaultConfiguration(); +} diff --git a/src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java b/src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java new file mode 100644 index 0000000..c071a8e --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import org.apache.commons.net.ftp.Configurable; +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFileEntryParser; + + +/** + * This is the default implementation of the + * FTPFileEntryParserFactory interface. This is the + * implementation that will be used by + * org.apache.commons.net.ftp.FTPClient.listFiles() + * if no other implementation has been specified. + * + * @see org.apache.commons.net.ftp.FTPClient#listFiles + * @see org.apache.commons.net.ftp.FTPClient#setParserFactory + */ +public class DefaultFTPFileEntryParserFactory + implements FTPFileEntryParserFactory +{ + private FTPClientConfig config = null; + + /** + * This default implementation of the FTPFileEntryParserFactory + * interface works according to the following logic: + * First it attempts to interpret the supplied key as a fully + * qualified classname of a class implementing the + * FTPFileEntryParser interface. If that succeeds, a parser + * object of this class is instantiated and is returned; + * otherwise it attempts to interpret the key as an identirier + * commonly used by the FTP SYST command to identify systems. + *

+ * If key is not recognized as a fully qualified + * classname known to the system, this method will then attempt + * to see whether it contains a string identifying one of + * the known parsers. This comparison is case-insensitive. + * The intent here is where possible, to select as keys strings + * which are returned by the SYST command on the systems which + * the corresponding parser successfully parses. This enables + * this factory to be used in the auto-detection system. + *

+ * + * @param key should be a fully qualified classname corresponding to + * a class implementing the FTPFileEntryParser interface
+ * OR
+ * a string containing (case-insensitively) one of the + * following keywords: + *

    + *
  • {@link FTPClientConfig#SYST_UNIX UNIX}
  • + *
  • {@link FTPClientConfig#SYST_NT WINDOWS}
  • + *
  • {@link FTPClientConfig#SYST_OS2 OS/2}
  • + *
  • {@link FTPClientConfig#SYST_OS400 OS/400}
  • + *
  • {@link FTPClientConfig#SYST_VMS VMS}
  • + *
  • {@link FTPClientConfig#SYST_MVS MVS}
  • + *
  • {@link FTPClientConfig#SYST_NETWARE}
  • + *
+ * @return the FTPFileEntryParser corresponding to the supplied key. + * @throws ParserInitializationException thrown if for any reason the factory cannot resolve + * the supplied key into an FTPFileEntryParser. + * @see FTPFileEntryParser + */ + public FTPFileEntryParser createFileEntryParser(String key) + { + if (key == null) + throw new ParserInitializationException("Parser key cannot be null"); + + Class parserClass = null; + FTPFileEntryParser parser = null; + try + { + parserClass = Class.forName(key); + parser = (FTPFileEntryParser) parserClass.newInstance(); + } + catch (ClassNotFoundException e) + { + try + { + String ukey = null; + if (null != key) + { + ukey = key.toUpperCase(java.util.Locale.ENGLISH); + } + if ((ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) + || (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0)) + { + parser = createUnixFTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) + { + parser = createVMSVersioningFTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) + { + parser = createNTFTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) + { + parser = createOS2FTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 || + ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) + { + parser = createOS400FTPEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) + { + parser = createMVSEntryParser(); + } + else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) + { + parser = createNetwareFTPEntryParser(); + } + else + { + throw new ParserInitializationException("Unknown parser type: " + key); + } + } + catch (NoClassDefFoundError nf) { + throw new ParserInitializationException("Error initializing parser", nf); + } + + } + catch (NoClassDefFoundError e) + { + throw new ParserInitializationException("Error initializing parser", e); + } + catch (ClassCastException e) + { + throw new ParserInitializationException(parserClass.getName() + + " does not implement the interface " + + "org.apache.commons.net.ftp.FTPFileEntryParser.", e); + } + catch (Throwable e) + { + throw new ParserInitializationException("Error initializing parser", e); + } + + if (parser instanceof Configurable) { + ((Configurable)parser).configure(this.config); + } + return parser; + } + + /** + *

Implementation extracts a key from the supplied + * {@link FTPClientConfig FTPClientConfig} + * parameter and creates an object implementing the + * interface FTPFileEntryParser and uses the supplied configuration + * to configure it. + *

+ * Note that this method will generally not be called in scenarios + * that call for autodetection of parser type but rather, for situations + * where the user knows that the server uses a non-default configuration + * and knows what that configuration is. + *

+ * @param config A {@link FTPClientConfig FTPClientConfig} + * used to configure the parser created + * + * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. + * @exception ParserInitializationException + * Thrown on any exception in instantiation + * @since 1.4 + */ + public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) + throws ParserInitializationException + { + this.config = config; + String key = config.getServerSystemKey(); + return createFileEntryParser(key); + } + + + public FTPFileEntryParser createUnixFTPEntryParser() + { + return new UnixFTPEntryParser(); + } + + public FTPFileEntryParser createVMSVersioningFTPEntryParser() + { + return new VMSVersioningFTPEntryParser(); + } + + public FTPFileEntryParser createNetwareFTPEntryParser() { + return new NetwareFTPEntryParser(); + } + + public FTPFileEntryParser createNTFTPEntryParser() + { + if (config != null && FTPClientConfig.SYST_NT.equals( + config.getServerSystemKey())) + { + return new NTFTPEntryParser(); + } else { + return new CompositeFileEntryParser(new FTPFileEntryParser[] + { + new NTFTPEntryParser(), + new UnixFTPEntryParser() + }); + } + } + + public FTPFileEntryParser createOS2FTPEntryParser() + { + return new OS2FTPEntryParser(); + } + + public FTPFileEntryParser createOS400FTPEntryParser() + { + if (config != null && + FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) + { + return new OS400FTPEntryParser(); + } else { + return new CompositeFileEntryParser(new FTPFileEntryParser[] + { + new OS400FTPEntryParser(), + new UnixFTPEntryParser() + }); + } + } + + public FTPFileEntryParser createMVSEntryParser() + { + return new MVSFTPEntryParser(); + } + + + +} + diff --git a/src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java new file mode 100644 index 0000000..c7e6da7 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.util.Calendar; + +import org.apache.commons.net.ftp.FTPFile; + +/** + * Parser for the Connect Enterprise Unix FTP Server From Sterling Commerce. + * Here is a sample of the sort of output line this parser processes: + * "-C--E-----FTP B QUA1I1 18128 41 Aug 12 13:56 QUADTEST" + *

+ * Note: EnterpriseUnixFTPEntryParser can only be instantiated through the + * DefaultFTPParserFactory by classname. It will not be chosen + * by the autodetection scheme. + * + * @version $Id: EnterpriseUnixFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @author Winston Ojeda + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + */ +public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl +{ + + /** + * months abbreviations looked for by this parser. Also used + * to determine which month has been matched by the parser. + */ + private static final String MONTHS = + "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; + + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "(([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])" + + "([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z]))" + + "(\\S*)\\s*" + + "(\\S+)\\s*" + + "(\\S*)\\s*" + + "(\\d*)\\s*" + + "(\\d*)\\s*" + + MONTHS + + "\\s*" + + "((?:[012]\\d*)|(?:3[01]))\\s*" + + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" + + "(\\S*)(\\s*.*)"; + + /** + * The sole constructor for a EnterpriseUnixFTPEntryParser object. + * + */ + public EnterpriseUnixFTPEntryParser() + { + super(REGEX); + } + + /** + * Parses a line of a unix FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If + * the file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + * + * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + + FTPFile file = new FTPFile(); + file.setRawListing(entry); + + if (matches(entry)) + { + String usr = group(14); + String grp = group(15); + String filesize = group(16); + String mo = group(17); + String da = group(18); + String yr = group(20); + String hr = group(21); + String min = group(22); + String name = group(23); + + file.setType(FTPFile.FILE_TYPE); + file.setUser(usr); + file.setGroup(grp); + try + { + file.setSize(Long.parseLong(filesize)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, + 0); + cal.set(Calendar.MINUTE, + 0); + cal.set(Calendar.HOUR_OF_DAY, + 0); + try + { + + int pos = MONTHS.indexOf(mo); + int month = pos / 4; + if (yr != null) + { + // it's a year + cal.set(Calendar.YEAR, + Integer.parseInt(yr)); + } + else + { + // it must be hour/minute or we wouldn't have matched + int year = cal.get(Calendar.YEAR); + + // if the month we're reading is greater than now, it must + // be last year + if (cal.get(Calendar.MONTH) < month) + { + year--; + } + cal.set(Calendar.YEAR, + year); + cal.set(Calendar.HOUR_OF_DAY, + Integer.parseInt(hr)); + cal.set(Calendar.MINUTE, + Integer.parseInt(min)); + } + cal.set(Calendar.MONTH, + month); + cal.set(Calendar.DATE, + Integer.parseInt(da)); + file.setTimestamp(cal); + } + catch (NumberFormatException e) + { + // do nothing, date will be uninitialized + } + file.setName(name); + + return file; + } + return null; + } +} diff --git a/src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java b/src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java new file mode 100644 index 0000000..e80ec0d --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFileEntryParser; + +/** + * The interface describes a factory for creating FTPFileEntryParsers. + * @since 1.2 + */ +public interface FTPFileEntryParserFactory +{ + /** + * Implementation should be a method that decodes the + * supplied key and creates an object implementing the + * interface FTPFileEntryParser. + * + * @param key A string that somehow identifies an + * FTPFileEntryParser to be created. + * + * @return the FTPFileEntryParser created. + * @exception ParserInitializationException + * Thrown on any exception in instantiation + */ + public FTPFileEntryParser createFileEntryParser(String key) + throws ParserInitializationException; + + /** + *

+ * Implementation should be a method that extracts + * a key from the supplied {@link FTPClientConfig FTPClientConfig} + * parameter and creates an object implementing the + * interface FTPFileEntryParser and uses the supplied configuration + * to configure it. + *

+ * Note that this method will generally not be called in scenarios + * that call for autodetection of parser type but rather, for situations + * where the user knows that the server uses a non-default configuration + * and knows what that configuration is. + *

+ * + * @param config A {@link FTPClientConfig FTPClientConfig} + * used to configure the parser created + * + * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. + * @exception ParserInitializationException + * Thrown on any exception in instantiation + * @since 1.4 + */ + public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) + throws ParserInitializationException; + +} diff --git a/src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java b/src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java new file mode 100644 index 0000000..40b46cb --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; +import java.util.Calendar; + +/** + * This interface specifies the concept of parsing an FTP server's + * timestamp. + * @since 1.4 + */ +public interface FTPTimestampParser { + + /** + * the default default date format. + */ + public static final String DEFAULT_SDF = UnixFTPEntryParser.DEFAULT_DATE_FORMAT; + /** + * the default recent date format. + */ + public static final String DEFAULT_RECENT_SDF = UnixFTPEntryParser.DEFAULT_RECENT_DATE_FORMAT; + + /** + * Parses the supplied datestamp parameter. This parameter typically would + * have been pulled from a longer FTP listing via the regular expression + * mechanism + * @param timestampStr - the timestamp portion of the FTP directory listing + * to be parsed + * @return a java.util.Calendar object initialized to the date + * parsed by the parser + * @throws ParseException if none of the parser mechanisms belonging to + * the implementor can parse the input. + */ + public Calendar parseTimestamp(String timestampStr) throws ParseException; + +} diff --git a/src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java b/src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java new file mode 100644 index 0000000..02a0cc8 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +import org.apache.commons.net.ftp.Configurable; +import org.apache.commons.net.ftp.FTPClientConfig; + +/** + * Default implementation of the {@link FTPTimestampParser FTPTimestampParser} + * interface also implements the {@link org.apache.commons.net.ftp.Configurable Configurable} + * interface to allow the parsing to be configured from the outside. + * + * @see ConfigurableFTPFileEntryParserImpl + * @since 1.4 + */ +public class FTPTimestampParserImpl implements + FTPTimestampParser, Configurable +{ + + + private SimpleDateFormat defaultDateFormat; + private SimpleDateFormat recentDateFormat; + private boolean lenientFutureDates = false; + + + /** + * The only constructor for this class. + */ + public FTPTimestampParserImpl() { + setDefaultDateFormat(DEFAULT_SDF); + setRecentDateFormat(DEFAULT_RECENT_SDF); + } + + /** + * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} + * in the {@link FTPTimestampParser FTPTimestampParser} interface + * according to this algorithm: + * + * If the recentDateFormat member has been defined, try to parse the + * supplied string with that. If that parse fails, or if the recentDateFormat + * member has not been defined, attempt to parse with the defaultDateFormat + * member. If that fails, throw a ParseException. + * + * This method allows a {@link Calendar} instance to be passed in which represents the + * current (system) time. + * + * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String) + * + * @param timestampStr The timestamp to be parsed + */ + public Calendar parseTimestamp(String timestampStr) throws ParseException { + Calendar now = Calendar.getInstance(); + return parseTimestamp(timestampStr, now); + } + + /** + * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} + * in the {@link FTPTimestampParser FTPTimestampParser} interface + * according to this algorithm: + * + * If the recentDateFormat member has been defined, try to parse the + * supplied string with that. If that parse fails, or if the recentDateFormat + * member has not been defined, attempt to parse with the defaultDateFormat + * member. If that fails, throw a ParseException. + * + * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String) + * @param timestampStr The timestamp to be parsed + * @param serverTime The current time for the server + * @since 1.5 + */ + public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { + Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it + now.setTimeZone(this.getServerTimeZone()); + Calendar working = (Calendar) now.clone(); + working.setTimeZone(getServerTimeZone()); + ParsePosition pp = new ParsePosition(0); + + Date parsed = null; + if (recentDateFormat != null) { + if (lenientFutureDates) { + // add a day to "now" so that "slop" doesn't cause a date + // slightly in the future to roll back a full year. (Bug 35181) + now.add(Calendar.DATE, 1); + } + parsed = recentDateFormat.parse(timestampStr, pp); + } + if (parsed != null && pp.getIndex() == timestampStr.length()) + { + working.setTime(parsed); + working.set(Calendar.YEAR, now.get(Calendar.YEAR)); + + if (working.after(now)) { + working.add(Calendar.YEAR, -1); + } + } else { + // Temporarily add the current year to the short date time + // to cope with short-date leap year strings. + // e.g. Java's DateFormatter will assume that "Feb 29 12:00" refers to + // Feb 29 1970 (an invalid date) rather than a potentially valid leap year date. + // This is pretty bad hack to work around the deficiencies of the JDK date/time classes. + if (recentDateFormat != null) { + pp = new ParsePosition(0); + int year = now.get(Calendar.YEAR); + String timeStampStrPlusYear = timestampStr + " " + year; + SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy", + recentDateFormat.getDateFormatSymbols()); + hackFormatter.setLenient(false); + hackFormatter.setTimeZone(recentDateFormat.getTimeZone()); + parsed = hackFormatter.parse(timeStampStrPlusYear, pp); + } + if (parsed != null && pp.getIndex() == timestampStr.length() + 5) { + working.setTime(parsed); + } + else { + pp = new ParsePosition(0); + parsed = defaultDateFormat.parse(timestampStr, pp); + // note, length checks are mandatory for us since + // SimpleDateFormat methods will succeed if less than + // full string is matched. They will also accept, + // despite "leniency" setting, a two-digit number as + // a valid year (e.g. 22:04 will parse as 22 A.D.) + // so could mistakenly confuse an hour with a year, + // if we don't insist on full length parsing. + if (parsed != null && pp.getIndex() == timestampStr.length()) { + working.setTime(parsed); + } else { + throw new ParseException( + "Timestamp could not be parsed with older or recent DateFormat", + pp.getIndex()); + } + } + } + return working; + } + + /** + * @return Returns the defaultDateFormat. + */ + public SimpleDateFormat getDefaultDateFormat() { + return defaultDateFormat; + } + /** + * @return Returns the defaultDateFormat pattern string. + */ + public String getDefaultDateFormatString() { + return defaultDateFormat.toPattern(); + } + /** + * @param defaultDateFormat The defaultDateFormat to be set. + */ + private void setDefaultDateFormat(String format) { + if (format != null) { + this.defaultDateFormat = new SimpleDateFormat(format); + this.defaultDateFormat.setLenient(false); + } + } + /** + * @return Returns the recentDateFormat. + */ + public SimpleDateFormat getRecentDateFormat() { + return recentDateFormat; + } + /** + * @return Returns the recentDateFormat. + */ + public String getRecentDateFormatString() { + return recentDateFormat.toPattern(); + } + /** + * @param recentDateFormat The recentDateFormat to set. + */ + private void setRecentDateFormat(String format) { + if (format != null) { + this.recentDateFormat = new SimpleDateFormat(format); + this.recentDateFormat.setLenient(false); + } + } + + /** + * @return returns an array of 12 strings representing the short + * month names used by this parse. + */ + public String[] getShortMonths() { + return defaultDateFormat.getDateFormatSymbols().getShortMonths(); + } + + + /** + * @return Returns the serverTimeZone used by this parser. + */ + public TimeZone getServerTimeZone() { + return this.defaultDateFormat.getTimeZone(); + } + /** + * sets a TimeZone represented by the supplied ID string into all + * of the parsers used by this server. + * @param serverTimeZone Time Id java.util.TimeZone id used by + * the ftp server. If null the client's local time zone is assumed. + */ + private void setServerTimeZone(String serverTimeZoneId) { + TimeZone serverTimeZone = TimeZone.getDefault(); + if (serverTimeZoneId != null) { + serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId); + } + this.defaultDateFormat.setTimeZone(serverTimeZone); + if (this.recentDateFormat != null) { + this.recentDateFormat.setTimeZone(serverTimeZone); + } + } + + /** + * Implementation of the {@link Configurable Configurable} + * interface. Configures this FTPTimestampParser according + * to the following logic: + *

+ * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat} + * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat} + * to values supplied in the config based on month names configured as follows: + *

    + *
  • If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString} + * has been supplied in the config, use that to parse parse timestamps.
  • + *
  • Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode} + * has been supplied in the config, use the month names represented + * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language} + * to parse timestamps.
  • + *
  • otherwise use default English month names
  • + *

+ * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId} + * has been supplied via the config, set that into all date formats that have + * been configured. + *

+ */ + public void configure(FTPClientConfig config) { + DateFormatSymbols dfs = null; + + String languageCode = config.getServerLanguageCode(); + String shortmonths = config.getShortMonthNames(); + if (shortmonths != null) { + dfs = FTPClientConfig.getDateFormatSymbols(shortmonths); + } else if (languageCode != null) { + dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode); + } else { + dfs = FTPClientConfig.lookupDateFormatSymbols("en"); + } + + + String recentFormatString = config.getRecentDateFormatStr(); + if (recentFormatString == null) { + this.recentDateFormat = null; + } else { + this.recentDateFormat = new SimpleDateFormat(recentFormatString, dfs); + this.recentDateFormat.setLenient(false); + } + + String defaultFormatString = config.getDefaultDateFormatStr(); + if (defaultFormatString == null) { + throw new IllegalArgumentException("defaultFormatString cannot be null"); + } + this.defaultDateFormat = new SimpleDateFormat(defaultFormatString, dfs); + this.defaultDateFormat.setLenient(false); + + setServerTimeZone(config.getServerTimeZoneId()); + + this.lenientFutureDates = config.isLenientFutureDates(); + } + /** + * @return Returns the lenientFutureDates. + */ + boolean isLenientFutureDates() { + return lenientFutureDates; + } + /** + * @param lenientFutureDates The lenientFutureDates to set. + */ + void setLenientFutureDates(boolean lenientFutureDates) { + this.lenientFutureDates = lenientFutureDates; + } +} diff --git a/src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java new file mode 100644 index 0000000..cd87e6e --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java @@ -0,0 +1,495 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; +import java.util.List; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for IBM zOS/MVS + * Systems. + * + * @author Henrik Sorensen + * @author Jeff Nadler + * @author William Noto + * + * @version $Id: MVSFTPEntryParser.java 658520 2008-05-21 01:14:11Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for + * usage instructions) + */ +public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { + + static final int UNKNOWN_LIST_TYPE = -1; + static final int FILE_LIST_TYPE = 0; + static final int MEMBER_LIST_TYPE = 1; + static final int UNIX_LIST_TYPE = 2; + static final int JES_LEVEL_1_LIST_TYPE = 3; + static final int JES_LEVEL_2_LIST_TYPE = 4; + + private int isType = UNKNOWN_LIST_TYPE; + + /** + * Fallback parser for Unix-style listings + */ + private UnixFTPEntryParser unixFTPEntryParser; + + /** + * Dates are ignored for file lists, but are used for member lists where + * possible + */ + static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm"; // 2001/09/18 + // 13:52 + + /** + * Matches these entries: Volume Unit Referred Ext Used Recfm Lrecl BlkSz + * Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 80 PS MDI.OKL.WORK + * + */ + static final String FILE_LIST_REGEX = "\\S+\\s+" + // volume + // ignored + "\\S+\\s+" + // unit - ignored + "\\S+\\s+" + // access date - ignored + "\\S+\\s+" + // extents -ignored + "\\S+\\s+" + // used - ignored + "[FV]\\S*\\s+" + // recfm - must start with F or V + "\\S+\\s+" + // logical record length -ignored + "\\S+\\s+" + // block size - ignored + "(PS|PO|PO-E)\\s+" + // Dataset organisation. Many exist + // but only support: PS, PO, PO-E + "(\\S+)\\s*"; // Dataset Name (file name) + + /** + * Matches these entries: Name VV.MM Created Changed Size Init Mod Id + * TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 0 KIL001 + */ + static final String MEMBER_LIST_REGEX = "(\\S+)\\s+" + // name + "\\S+\\s+" + // version, modification (ignored) + "\\S+\\s+" + // create date (ignored) + "(\\S+)\\s+" + // modification date + "(\\S+)\\s+" + // modification time + "\\S+\\s+" + // size in lines (ignored) + "\\S+\\s+" + // size in lines at creation(ignored) + "\\S+\\s+" + // lines modified (ignored) + "\\S+\\s*"; // id of user who modified (ignored) + + /** + * Matches these entries, note: no header: IBMUSER1 JOB01906 OUTPUT 3 Spool + * Files 012345678901234567890123456789012345678901234 1 2 3 4 + */ + static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job + // name + // ignored + "(\\S+)\\s+" + // job number + "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) + "(\\S+)\\s+" + // number of spool files + "(\\S+)\\s+" + // Text "Spool" ignored + "(\\S+)\\s*" // Text "Files" ignored + ; + + /** + * JES INTERFACE LEVEL 2 parser Matches these entries: JOBNAME JOBID OWNER + * STATUS CLASS IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool files + * IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files + * 012345678901234567890123456789012345678901234 1 2 3 4 + * 012345678901234567890123456789012345678901234567890 + */ + + static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job + // name + // ignored + "(\\S+)\\s+" + // job number + "(\\S+)\\s+" + // owner ignored + "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored + "(\\S+)\\s+" + // job class ignored + "(\\S+).*" // rest ignored + ; + + /* + * --------------------------------------------------------------------- + * Very brief and incomplete description of the zOS/MVS-filesystem. (Note: + * "zOS" is the operating system on the mainframe, and is the new name for + * MVS) + * + * The filesystem on the mainframe does not have hierarchal structure as for + * example the unix filesystem. For a more comprehensive description, please + * refer to the IBM manuals + * + * @LINK: + * http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dgt2d440/CONTENTS + * + * + * Dataset names ============= + * + * A dataset name consist of a number of qualifiers separated by '.', each + * qualifier can be at most 8 characters, and the total length of a dataset + * can be max 44 characters including the dots. + * + * + * Dataset organisation ==================== + * + * A dataset represents a piece of storage allocated on one or more disks. + * The structure of the storage is described with the field dataset + * organinsation (DSORG). There are a number of dataset organisations, but + * only two are usable for FTP transfer. + * + * DSORG: PS: sequential, or flat file PO: partitioned dataset PO-E: + * extended partitioned dataset + * + * The PS file is just a flat file, as you would find it on the unix file + * system. + * + * The PO and PO-E files, can be compared to a single level directory + * structure. A PO file consist of a number of dataset members, or files if + * you will. It is possible to CD into the file, and to retrieve the + * individual members. + * + * + * Dataset record format ===================== + * + * The physical layout of the dataset is described on the dataset itself. + * There are a number of record formats (RECFM), but just a few is relavant + * for the FTP transfer. + * + * Any one beginning with either F or V can safely used by FTP transfer. All + * others should only be used with great care, so this version will just + * ignore the other record formats. F means a fixed number of records per + * allocated storage, and V means a variable number of records. + * + * + * Other notes =========== + * + * The file system supports automatically backup and retrieval of datasets. + * If a file is backed up, the ftp LIST command will return: ARCIVE Not + * Direct Access Device KJ.IOP998.ERROR.PL.UNITTEST + * + * + * Implementation notes ==================== + * + * Only datasets that have dsorg PS, PO or PO-E and have recfm beginning + * with F or V, is fully parsed. + * + * The following fields in FTPFile is used: FTPFile.Rawlisting: Always set. + * FTPFile.Type: DIRECTORY_TYPE or FILE_TYPE or UNKNOWN FTPFile.Name: name + * FTPFile.Timestamp: change time or null + * + * + * + * Additional information ====================== + * + * The MVS ftp server supports a number of features via the FTP interface. + * The features are controlled with the FTP command quote site filetype= + * SEQ is the default and used for normal file transfer JES is used to + * interact with the Job Entry Subsystem (JES) similar to a job scheduler + * DB2 is used to interact with a DB2 subsystem + * + * This parser supports SEQ and JES. + * + * + * + * + * + * + */ + + /** + * The sole constructor for a MVSFTPEntryParser object. + * + */ + public MVSFTPEntryParser() { + super(""); // note the regex is set in preParse. + super.configure(null); // configure parser with default configurations + } + + /** + * Parses a line of an z/OS - MVS FTP server file listing and converts it + * into a usable format in the form of an FTPFile instance. + * If the file listing line doesn't describe a file, then + * null is returned. Otherwise a FTPFile + * instance representing the file is returned. + * + * @param entry + * A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) { + boolean isParsed = false; + FTPFile f = new FTPFile(); + + if (isType == FILE_LIST_TYPE) + isParsed = parseFileList(f, entry); + else if (isType == MEMBER_LIST_TYPE) { + isParsed = parseMemberList(f, entry); + if (!isParsed) + isParsed = parseSimpleEntry(f, entry); + } else if (isType == UNIX_LIST_TYPE) { + isParsed = parseUnixList(f, entry); + } else if (isType == JES_LEVEL_1_LIST_TYPE) { + isParsed = parseJeslevel1List(f, entry); + } else if (isType == JES_LEVEL_2_LIST_TYPE) { + isParsed = parseJeslevel2List(f, entry); + } + + if (!isParsed) + f = null; + + return f; + } + + /** + * Parse entries representing a dataset list. Only datasets with DSORG PS or + * PO or PO-E and with RECFM F* or V* will be parsed. + * + * Format of ZOS/MVS file list: 1 2 3 4 5 6 7 8 9 10 Volume Unit Referred + * Ext Used Recfm Lrecl BlkSz Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 + * 80 PS MDI.OKL.WORK ARCIVE Not Direct Access Device + * KJ.IOP998.ERROR.PL.UNITTEST B1N231 3390 2006/03/20 1 15 VB 256 27998 PO + * PLU B1N231 3390 2006/03/20 1 15 VB 256 27998 PO-E PLB + * + * ----------------------------------- Group within Regex [1] Volume [2] + * Unit [3] Referred [4] Ext: number of extents [5] Used [6] Recfm: Record + * format [7] Lrecl: Logical record length [8] BlkSz: Block size [9] Dsorg: + * Dataset organisation. Many exists but only support: PS, PO, PO-E [10] + * Dsname: Dataset name + * + * Note: When volume is ARCIVE, it means the dataset is stored somewhere in + * a tape archive. These entries is currently not supported by this parser. + * A null value is returned. + * + * @param file + * will be updated with Name, Type, Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseFileList(FTPFile file, String entry) { + if (matches(entry)) { + file.setRawListing(entry); + String name = group(2); + String dsorg = group(1); + file.setName(name); + + // DSORG + if ("PS".equals(dsorg)) { + file.setType(FTPFile.FILE_TYPE); + } + else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) { + // regex already ruled out anything other than PO or PO-E + file.setType(FTPFile.DIRECTORY_TYPE); + } + else { + return false; + } + + return true; + } + + return false; + } + + /** + * Parse entries within a partitioned dataset. + * + * Format of a memberlist within a PDS: 1 2 3 4 5 6 7 8 9 Name VV.MM Created + * Changed Size Init Mod Id TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 + * 0 KIL001 TBTOOL 01.12 2002/09/12 2004/11/26 19:54 51 28 0 KIL001 + * + * ------------------------------------------- [1] Name [2] VV.MM: Version . + * modification [3] Created: yyyy / MM / dd [4,5] Changed: yyyy / MM / dd + * HH:mm [6] Size: number of lines [7] Init: number of lines when first + * created [8] Mod: number of modified lines a last save [9] Id: User id for + * last update + * + * + * @param file + * will be updated with Name, Type and Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseMemberList(FTPFile file, String entry) { + if (matches(entry)) { + file.setRawListing(entry); + String name = group(1); + String datestr = group(2) + " " + group(3); + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + try { + file.setTimestamp(super.parseTimestamp(datestr)); + } catch (ParseException e) { + e.printStackTrace(); + // just ignore parsing errors. + // TODO check this is ok + return false; // this is a parsing failure too. + } + return true; + } + + return false; + } + + /** + * Assigns the name to the first word of the entry. Only to be used from a + * safe context, for example from a memberlist, where the regex for some + * reason fails. Then just assign the name field of FTPFile. + * + * @param file + * @param entry + * @return + */ + private boolean parseSimpleEntry(FTPFile file, String entry) { + if (entry != null && entry.length() > 0) { + file.setRawListing(entry); + String name = entry.split(" ")[0]; + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + return true; + } + return false; + } + + /** + * Parse the entry as a standard unix file. Using the UnixFTPEntryParser. + * + * @param file + * @param entry + * @return true: entry is parsed, false: entry could not be parsed. + */ + private boolean parseUnixList(FTPFile file, String entry) { + file = unixFTPEntryParser.parseFTPEntry(entry); + if (file == null) + return false; + return true; + } + + /** + * Matches these entries, note: no header: [1] [2] [3] [4] [5] IBMUSER1 + * JOB01906 OUTPUT 3 Spool Files + * 012345678901234567890123456789012345678901234 1 2 3 4 + * ------------------------------------------- Group in regex [1] Job name + * [2] Job number [3] Job status (INPUT,ACTIVE,OUTPUT) [4] Number of sysout + * files [5] The string "Spool Files" + * + * + * @param file + * will be updated with Name, Type and Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseJeslevel1List(FTPFile file, String entry) { + if (matches(entry)) { + if (group(3).equalsIgnoreCase("OUTPUT")) { + file.setRawListing(entry); + String name = group(2); /* Job Number, used by GET */ + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + return true; + } + } + + return false; + } + + /** + * Matches these entries, note: no header: [1] [2] [3] [4] [5] JOBNAME JOBID + * OWNER STATUS CLASS IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool + * files IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files + * 012345678901234567890123456789012345678901234 1 2 3 4 + * ------------------------------------------- Group in regex [1] Job name + * [2] Job number [3] Owner [4] Job status (INPUT,ACTIVE,OUTPUT) [5] Job + * Class [6] The rest + * + * + * @param file + * will be updated with Name, Type and Timestamp if parsed. + * @param entry zosDirectoryEntry + * @return true: entry was parsed, false: entry was not parsed. + */ + private boolean parseJeslevel2List(FTPFile file, String entry) { + if (matches(entry)) { + if (group(4).equalsIgnoreCase("OUTPUT")) { + file.setRawListing(entry); + String name = group(2); /* Job Number, used by GET */ + file.setName(name); + file.setType(FTPFile.FILE_TYPE); + return true; + } + } + + return false; + } + + /** + * preParse is called as part of the interface. Per definition is is called + * before the parsing takes place. Three kind of lists is recognize: + * z/OS-MVS File lists z/OS-MVS Member lists unix file lists + * @since 2.0 + */ + @Override + public List preParse(List orig) { + // simply remove the header line. Composite logic will take care of the + // two different types of + // list in short order. + if (orig != null && orig.size() > 0) { + String header = orig.get(0); + if (header.indexOf("Volume") >= 0 && header.indexOf("Dsname") >= 0) { + setType(FILE_LIST_TYPE); + super.setRegex(FILE_LIST_REGEX); + } else if (header.indexOf("Name") >= 0 && header.indexOf("Id") >= 0) { + setType(MEMBER_LIST_TYPE); + super.setRegex(MEMBER_LIST_REGEX); + } else if (header.indexOf("total") == 0) { + setType(UNIX_LIST_TYPE); + unixFTPEntryParser = new UnixFTPEntryParser(); + } else if (header.indexOf("Spool Files") >= 30) { + setType(JES_LEVEL_1_LIST_TYPE); + super.setRegex(JES_LEVEL_1_LIST_REGEX); + } else if (header.indexOf("JOBNAME") == 0 + && header.indexOf("JOBID") > 8) {// header contains JOBNAME JOBID OWNER // STATUS CLASS + setType(JES_LEVEL_2_LIST_TYPE); + super.setRegex(JES_LEVEL_2_LIST_REGEX); + } else { + setType(UNKNOWN_LIST_TYPE); + } + + if (isType != JES_LEVEL_1_LIST_TYPE) { // remove header is necessary + orig.remove(0); + } + } + + return orig; + } + + /** + * Explicitly set the type of listing being processed. + * @param type The listing type. + */ + void setType(int type) { + isType = type; + } + + /* + * @return + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig(FTPClientConfig.SYST_MVS, + DEFAULT_DATE_FORMAT, null, null, null, null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java new file mode 100644 index 0000000..b6bc75e --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for NT Systems. + * + * @author Winston Ojeda + * @author Steve Cohen + * @version $Id: NTFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + + private static final String DEFAULT_DATE_FORMAT + = "MM-dd-yy hh:mma"; //11-09-01 12:30PM + + + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "(\\S+)\\s+(\\S+)\\s+" + + "(?:()|([0-9]+))\\s+" + + "(\\S.*)"; + + /** + * The sole constructor for an NTFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public NTFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of an NTFTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public NTFTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + /** + * Parses a line of an NT FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + FTPFile f = new FTPFile(); + f.setRawListing(entry); + + if (matches(entry)) + { + String datestr = group(1)+" "+group(2); + String dirString = group(3); + String size = group(4); + String name = group(5); + try + { + f.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + if (null == name || name.equals(".") || name.equals("..")) + { + return (null); + } + f.setName(name); + + + if ("

".equals(dirString)) + { + f.setType(FTPFile.DIRECTORY_TYPE); + f.setSize(0); + } + else + { + f.setType(FTPFile.FILE_TYPE); + if (null != size) + { + f.setSize(Long.parseLong(size)); + } + } + return (f); + } + return null; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + public FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_NT, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java new file mode 100644 index 0000000..3cbea82 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of the proprietary + * extensions for Novell-specific operations are not supported. See + * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html + * for more details. + * + * @author Rory Winston + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + * @version $Id: NetwareFTPEntryParser.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 1.5 + */ +public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { + + /** + * Default date format is e.g. Feb 22 2006 + */ + private static final String DEFAULT_DATE_FORMAT = "MMM dd yyyy"; + + /** + * Default recent date format is e.g. Feb 22 17:32 + */ + private static final String DEFAULT_RECENT_DATE_FORMAT = "MMM dd HH:mm"; + + /** + * this is the regular expression used by this parser. + * Example: d [-W---F--] SCION_VOL2 512 Apr 13 23:12 VOL2 + */ + private static final String REGEX = "(d|-){1}\\s+" // Directory/file flag + + "\\[(.*)\\]\\s+" // Attributes + + "(\\S+)\\s+" + "(\\d+)\\s+" // Owner and size + + "(\\S+\\s+\\S+\\s+((\\d+:\\d+)|(\\d{4})))" // Long/short date format + + "\\s+(.*)"; // Filename (incl. spaces) + + /** + * The default constructor for a NetwareFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public NetwareFTPEntryParser() { + this(null); + } + + /** + * This constructor allows the creation of an NetwareFTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public NetwareFTPEntryParser(FTPClientConfig config) { + super(REGEX); + configure(config); + } + + /** + * Parses a line of an NetwareFTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ *

+ * Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: + *

    + *
  • S - Supervisor; All rights. + *
  • R - Read; Right to open and read or execute. + *
  • W - Write; Right to open and modify. + *
  • C - Create; Right to create; when assigned to a file, allows a deleted file to be recovered. + *
  • E - Erase; Right to delete. + *
  • M - Modify; Right to rename a file and to change attributes. + *
  • F - File Scan; Right to see directory or file listings. + *
  • A - Access Control; Right to modify trustee assignments and the Inherited Rights Mask. + *
+ * + * See here + * for more details + * + * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) { + + FTPFile f = new FTPFile(); + if (matches(entry)) { + String dirString = group(1); + String attrib = group(2); + String user = group(3); + String size = group(4); + String datestr = group(5); + String name = group(9); + + try { + f.setTimestamp(super.parseTimestamp(datestr)); + } catch (ParseException e) { + // intentionally do nothing + } + + //is it a DIR or a file + if (dirString.trim().equals("d")) { + f.setType(FTPFile.DIRECTORY_TYPE); + } else // Should be "-" + { + f.setType(FTPFile.FILE_TYPE); + } + + f.setUser(user); + + //set the name + f.setName(name.trim()); + + //set the size + f.setSize(Long.parseLong(size.trim())); + + // Now set the permissions (or at least a subset thereof - full permissions would probably require + // subclassing FTPFile and adding extra metainformation there) + if (attrib.indexOf("R") != -1) { + f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, + true); + } + if (attrib.indexOf("W") != -1) { + f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, + true); + } + + return (f); + } + return null; + + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, + DEFAULT_DATE_FORMAT, DEFAULT_RECENT_DATE_FORMAT, null, null, + null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java new file mode 100644 index 0000000..dc02ffb --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation of FTPFileEntryParser and FTPFileListParser for OS2 Systems. + * + * @author Winston Ojeda + * @author Steve Cohen + * @version $Id: OS2FTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl + +{ + + private static final String DEFAULT_DATE_FORMAT + = "MM-dd-yy HH:mm"; //11-09-01 12:30 + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "\\s*([0-9]+)\\s*" + + "(\\s+|[A-Z]+)\\s*" + + "(DIR|\\s+)\\s*" + + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ + + "(\\S.*)"; + + /** + * The default constructor for a OS2FTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public OS2FTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of an OS2FTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public OS2FTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + /** + * Parses a line of an OS2 FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + + FTPFile f = new FTPFile(); + if (matches(entry)) + { + String size = group(1); + String attrib = group(2); + String dirString = group(3); + String datestr = group(4)+" "+group(5); + String name = group(6); + try + { + f.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + //is it a DIR or a file + if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) + { + f.setType(FTPFile.DIRECTORY_TYPE); + } + else + { + f.setType(FTPFile.FILE_TYPE); + } + + + //set the name + f.setName(name.trim()); + + //set the size + f.setSize(Long.parseLong(size.trim())); + + return (f); + } + return null; + + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_OS2, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java new file mode 100644 index 0000000..66c370b --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * @version $Id: OS400FTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + */ + +public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + private static final String DEFAULT_DATE_FORMAT + = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24 + + + + private static final String REGEX = + "(\\S+)\\s+" // user + + "(\\d+)\\s+" // size + + "(\\S+)\\s+(\\S+)\\s+" // date stuff + + "(\\*\\S+)\\s+" // *STMF/*DIR + + "(\\S+/?)\\s*"; // filename + + + /** + * The default constructor for a OS400FTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public OS400FTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of an OS400FTPEntryParser object + * with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public OS400FTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + + public FTPFile parseFTPEntry(String entry) + { + + FTPFile file = new FTPFile(); + file.setRawListing(entry); + int type; + + if (matches(entry)) + { + String usr = group(1); + String filesize = group(2); + String datestr = group(3)+" "+group(4); + String typeStr = group(5); + String name = group(6); + + try + { + file.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + if (typeStr.equalsIgnoreCase("*STMF")) + { + type = FTPFile.FILE_TYPE; + } + else if (typeStr.equalsIgnoreCase("*DIR")) + { + type = FTPFile.DIRECTORY_TYPE; + } + else + { + type = FTPFile.UNKNOWN_TYPE; + } + + file.setType(type); + + file.setUser(usr); + + try + { + file.setSize(Long.parseLong(filesize)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + + if (name.endsWith("/")) + { + name = name.substring(0, name.length() - 1); + } + int pos = name.lastIndexOf('/'); + if (pos > -1) + { + name = name.substring(pos + 1); + } + + file.setName(name); + + return file; + } + return null; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_OS400, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/ParserInitializationException.java b/src/org/apache/commons/net/ftp/parser/ParserInitializationException.java new file mode 100644 index 0000000..8af9261 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/ParserInitializationException.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +/** + * This class encapsulates all errors that may be thrown by + * the process of an FTPFileEntryParserFactory creating and + * instantiating an FTPFileEntryParser. + */ +public class ParserInitializationException extends RuntimeException { + + /** + * Root exception that caused this to be thrown + */ + private final Throwable rootCause; + + /** + * Constucts a ParserInitializationException with just a message + * + * @param message Exception message + */ + public ParserInitializationException(String message) { + super(message); + this.rootCause = null; + } + + /** + * Constucts a ParserInitializationException with a message + * and a root cause. + * + * @param message Exception message + * @param rootCause root cause throwable that caused + * this to be thrown + */ + public ParserInitializationException(String message, Throwable rootCause) { + super(message); + this.rootCause = rootCause; + } + + /** + * returns the root cause of this exception or null + * if no root cause was specified. + * + * @return the root cause of this exception being thrown + */ + public Throwable getRootCause() { + return this.rootCause; + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java b/src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java new file mode 100644 index 0000000..5277444 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.net.ftp.parser; + +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.commons.net.ftp.FTPFileEntryParserImpl; + +/** + * This abstract class implements both the older FTPFileListParser and + * newer FTPFileEntryParser interfaces with default functionality. + * All the classes in the parser subpackage inherit from this. + * + * This is the base for all regular based FTPFileEntryParser + * + * @author Steve Cohen + */ +public abstract class RegexFTPFileEntryParserImpl extends + FTPFileEntryParserImpl { + /** + * internal pattern the matcher tries to match, representing a file + * entry + */ + private Pattern pattern = null; + + /** + * internal match result used by the parser + */ + private MatchResult result = null; + + /** + * Internal PatternMatcher object used by the parser. It has protected + * scope in case subclasses want to make use of it for their own purposes. + */ + protected Matcher _matcher_ = null; + + /** + * The constructor for a RegexFTPFileEntryParserImpl object. + * + * @param regex The regular expression with which this object is + * initialized. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen in + * normal conditions. It it is seen, this is a sign that a subclass has + * been created with a bad regular expression. Since the parser must be + * created before use, this means that any bad parser subclasses created + * from this will bomb very quickly, leading to easy detection. + */ + + public RegexFTPFileEntryParserImpl(String regex) { + super(); + setRegex(regex); + } + + /** + * Convenience method delegates to the internal MatchResult's matches() + * method. + * + * @param s the String to be matched + * @return true if s matches this object's regular expression. + */ + + public boolean matches(String s) { + this.result = null; + _matcher_ = pattern.matcher(s); + if (_matcher_.matches()) { + this.result = _matcher_.toMatchResult(); + } + return null != this.result; + } + + /** + * Convenience method + * + * @return the number of groups() in the internal MatchResult. + */ + + public int getGroupCnt() { + if (this.result == null) { + return 0; + } + return this.result.groupCount(); + } + + /** + * Convenience method delegates to the internal MatchResult's group() + * method. + * + * @param matchnum match group number to be retrieved + * + * @return the content of the matchnum'th group of the internal + * match or null if this method is called without a match having + * been made. + */ + public String group(int matchnum) { + if (this.result == null) { + return null; + } + return this.result.group(matchnum); + } + + /** + * For debugging purposes - returns a string shows each match group by + * number. + * + * @return a string shows each match group by number. + */ + + public String getGroupsAsString() { + StringBuffer b = new StringBuffer(); + for (int i = 1; i <= this.result.groupCount(); i++) { + b.append(i).append(") ").append(this.result.group(i)).append( + System.getProperty("line.separator")); + } + return b.toString(); + } + + /** + * Alter the current regular expression being utilised for entry parsing + * and create a new {@link Pattern} instance. + * @param regex The new regular expression + * @return + * @since 2.0 + */ + public boolean setRegex(String regex) { + try { + pattern = Pattern.compile(regex); + } catch (PatternSyntaxException pse) { + throw new IllegalArgumentException("Unparseable regex supplied: " + + regex); + } + return (pattern != null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java new file mode 100644 index 0000000..2a2a909 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java @@ -0,0 +1,295 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.text.ParseException; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; + +/** + * Implementation FTPFileEntryParser and FTPFileListParser for standard + * Unix Systems. + * + * This class is based on the logic of Daniel Savarese's + * DefaultFTPListParser, but adapted to use regular expressions and to fit the + * new FTPFileEntryParser interface. + * @version $Id: UnixFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + + static final String DEFAULT_DATE_FORMAT + = "MMM d yyyy"; //Nov 9 2001 + + static final String DEFAULT_RECENT_DATE_FORMAT + = "MMM d HH:mm"; //Nov 9 20:06 + + static final String NUMERIC_DATE_FORMAT + = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06 + + /** + * Some Linux distributions are now shipping an FTP server which formats + * file listing dates in an all-numeric format: + * "yyyy-MM-dd HH:mm. + * This is a very welcome development, and hopefully it will soon become + * the standard. However, since it is so new, for now, and possibly + * forever, we merely accomodate it, but do not make it the default. + *

+ * For now end users may specify this format only via + * UnixFTPEntryParser(FTPClientConfig). + * Steve Cohen - 2005-04-17 + */ + public static final FTPClientConfig NUMERIC_DATE_CONFIG = + new FTPClientConfig( + FTPClientConfig.SYST_UNIX, + NUMERIC_DATE_FORMAT, + null, null, null, null); + + /** + * this is the regular expression used by this parser. + * + * Permissions: + * r the file is readable + * w the file is writable + * x the file is executable + * - the indicated permission is not granted + * L mandatory locking occurs during access (the set-group-ID bit is + * on and the group execution bit is off) + * s the set-user-ID or set-group-ID bit is on, and the corresponding + * user or group execution bit is also on + * S undefined bit-state (the set-user-ID bit is on and the user + * execution bit is off) + * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and + * execution is on + * T the 1000 bit is turned on, and execution is off (undefined bit- + * state) + * e z/OS external link bit + */ + private static final String REGEX = + "([bcdelfmpSs-])" + +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" + + "(\\d+)\\s+" + + "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces) + + "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces) + + "(\\d+(?:,\\s*\\d+)?)\\s+" + + /* + numeric or standard format date + */ + + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+))\\s+" + + /* + year (for non-recent standard format) + or time (for numeric or recent standard format + */ + + "(\\d+(?::\\d+)?)\\s+" + + + "(\\S*)(\\s*.*)"; + + + /** + * The default constructor for a UnixFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public UnixFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of a UnixFTPEntryParser object with + * something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public UnixFTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + + /** + * Parses a line of a unix (standard) FTP server file listing and converts + * it into a usable format in the form of an FTPFile + * instance. If the file listing line doesn't describe a file, + * null is returned, otherwise a FTPFile + * instance representing the files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) { + FTPFile file = new FTPFile(); + file.setRawListing(entry); + int type; + boolean isDevice = false; + + if (matches(entry)) + { + String typeStr = group(1); + String hardLinkCount = group(15); + String usr = group(16); + String grp = group(17); + String filesize = group(18); + String datestr = group(19) + " " + group(20); + String name = group(21); + String endtoken = group(22); + + try + { + file.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + // bcdlfmpSs- + switch (typeStr.charAt(0)) + { + case 'd': + type = FTPFile.DIRECTORY_TYPE; + break; + case 'e': + type = FTPFile.SYMBOLIC_LINK_TYPE; + break; + case 'l': + type = FTPFile.SYMBOLIC_LINK_TYPE; + break; + case 'b': + case 'c': + isDevice = true; + // break; - fall through + case 'f': + case '-': + type = FTPFile.FILE_TYPE; + break; + default: + type = FTPFile.UNKNOWN_TYPE; + } + + file.setType(type); + + int g = 4; + for (int access = 0; access < 3; access++, g += 4) + { + // Use != '-' to avoid having to check for suid and sticky bits + file.setPermission(access, FTPFile.READ_PERMISSION, + (!group(g).equals("-"))); + file.setPermission(access, FTPFile.WRITE_PERMISSION, + (!group(g + 1).equals("-"))); + + String execPerm = group(g + 2); + if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) + { + file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); + } + else + { + file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); + } + } + + if (!isDevice) + { + try + { + file.setHardLinkCount(Integer.parseInt(hardLinkCount)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + } + + file.setUser(usr); + file.setGroup(grp); + + try + { + file.setSize(Long.parseLong(filesize)); + } + catch (NumberFormatException e) + { + // intentionally do nothing + } + + if (null == endtoken) + { + file.setName(name); + } + else + { + // oddball cases like symbolic links, file names + // with spaces in them. + name += endtoken; + if (type == FTPFile.SYMBOLIC_LINK_TYPE) + { + + int end = name.indexOf(" -> "); + // Give up if no link indicator is present + if (end == -1) + { + file.setName(name); + } + else + { + file.setName(name.substring(0, end)); + file.setLink(name.substring(end + 4)); + } + + } + else + { + file.setName(name); + } + } + return file; + } + return null; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_UNIX, + DEFAULT_DATE_FORMAT, + DEFAULT_RECENT_DATE_FORMAT, + null, null, null); + } + +} diff --git a/src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java new file mode 100644 index 0000000..1e55ede --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; +import java.util.StringTokenizer; + +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPListParseEngine; + +/** + * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. + * This is a sample of VMS LIST output + * + * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + *

+ * Note: VMSFTPEntryParser can only be instantiated through the + * DefaultFTPParserFactory by classname. It will not be chosen + * by the autodetection scheme. + * + *

+ * + * @author Winston Ojeda + * @author Steve Cohen + * @author Stephane ESTE-GRACIAS + * @version $Id: VMSFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ + * + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory + */ +public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl +{ + + private static final String DEFAULT_DATE_FORMAT + = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24 + + /** + * this is the regular expression used by this parser. + */ + private static final String REGEX = + "(.*;[0-9]+)\\s*" //1 file and version + + "(\\d+)/\\d+\\s*" //2 size/allocated + +"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time + + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner + + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; //9,10,11 Permissions (O,G,W) + // TODO - perhaps restrict permissions to [RWED]* ? + + + + /** + * Constructor for a VMSFTPEntryParser object. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public VMSFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of a VMSFTPEntryParser object with + * something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public VMSFTPEntryParser(FTPClientConfig config) + { + super(REGEX); + configure(config); + } + + + + /*** + * Parses an FTP server file listing and converts it into a usable format + * in the form of an array of FTPFile instances. If the + * file list contains no files, null should be + * returned, otherwise an array of FTPFile instances + * representing the files in the directory is returned. + *

+ * @param listStream The InputStream from which the file list should be + * read. + * @return The list of file information contained in the given path. null + * if the list could not be obtained or if there are no files in + * the directory. + * @exception IOException If an I/O error occurs reading the listStream. + ***/ + public FTPFile[] parseFileList(InputStream listStream) throws IOException { + FTPListParseEngine engine = new FTPListParseEngine(this); + engine.readServerList(listStream); + return engine.getFiles(); + } + + + + /** + * Parses a line of a VMS FTP server file listing and converts it into a + * usable format in the form of an FTPFile instance. If the + * file listing line doesn't describe a file, null is + * returned, otherwise a FTPFile instance representing the + * files in the directory is returned. + *

+ * @param entry A line of text from the file listing + * @return An FTPFile instance corresponding to the supplied entry + */ + public FTPFile parseFTPEntry(String entry) + { + //one block in VMS equals 512 bytes + long longBlock = 512; + + if (matches(entry)) + { + FTPFile f = new FTPFile(); + f.setRawListing(entry); + String name = group(1); + String size = group(2); + String datestr = group(3)+" "+group(4); + String owner = group(5); + String permissions[] = new String[3]; + permissions[0]= group(9); + permissions[1]= group(10); + permissions[2]= group(11); + try + { + f.setTimestamp(super.parseTimestamp(datestr)); + } + catch (ParseException e) + { + // intentionally do nothing + } + + + String grp; + String user; + StringTokenizer t = new StringTokenizer(owner, ","); + switch (t.countTokens()) { + case 1: + grp = null; + user = t.nextToken(); + break; + case 2: + grp = t.nextToken(); + user = t.nextToken(); + break; + default: + grp = null; + user = null; + } + + if (name.lastIndexOf(".DIR") != -1) + { + f.setType(FTPFile.DIRECTORY_TYPE); + } + else + { + f.setType(FTPFile.FILE_TYPE); + } + //set FTPFile name + //Check also for versions to be returned or not + if (isVersioning()) + { + f.setName(name); + } + else + { + name = name.substring(0, name.lastIndexOf(";")); + f.setName(name); + } + //size is retreived in blocks and needs to be put in bytes + //for us humans and added to the FTPFile array + long sizeInBytes = Long.parseLong(size) * longBlock; + f.setSize(sizeInBytes); + + f.setGroup(grp); + f.setUser(user); + //set group and owner + + //Set file permission. + //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain + //R (read) W (write) E (execute) D (delete) + + //iterate for OWNER GROUP WORLD permissions + for (int access = 0; access < 3; access++) + { + String permission = permissions[access]; + + f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); + f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); + f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); + } + + return f; + } + return null; + } + + + /** + * Reads the next entry using the supplied BufferedReader object up to + * whatever delemits one entry from the next. This parser cannot use + * the default implementation of simply calling BufferedReader.readLine(), + * because one entry may span multiple lines. + * + * @param reader The BufferedReader object from which entries are to be + * read. + * + * @return A string representing the next ftp entry or null if none found. + * @exception IOException thrown on any IO Error reading from the reader. + */ + @Override + public String readNextEntry(BufferedReader reader) throws IOException + { + String line = reader.readLine(); + StringBuffer entry = new StringBuffer(); + while (line != null) + { + if (line.startsWith("Directory") || line.startsWith("Total")) { + line = reader.readLine(); + continue; + } + + entry.append(line); + if (line.trim().endsWith(")")) + { + break; + } + line = reader.readLine(); + } + return (entry.length() == 0 ? null : entry.toString()); + } + + protected boolean isVersioning() { + return false; + } + + /** + * Defines a default configuration to be used when this class is + * instantiated without a {@link FTPClientConfig FTPClientConfig} + * parameter being specified. + * @return the default configuration for this parser. + */ + @Override + protected FTPClientConfig getDefaultConfiguration() { + return new FTPClientConfig( + FTPClientConfig.SYST_VMS, + DEFAULT_DATE_FORMAT, + null, null, null, null); + } + + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java new file mode 100644 index 0000000..cb25709 --- /dev/null +++ b/src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp.parser; + +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.commons.net.ftp.FTPClientConfig; + +/** + * Special implementation VMSFTPEntryParser with versioning turned on. + * This parser removes all duplicates and only leaves the version with the highest + * version number for each filename. + * + * This is a sample of VMS LIST output + * + * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", + *

+ * + * @author Winston Ojeda + * @author Stephane ESTE-GRACIAS + * @version $Id: VMSVersioningFTPEntryParser.java 636854 2008-03-13 19:55:01Z sebb $ + * + * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) + */ +public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser +{ + + private Matcher _preparse_matcher_; + private Pattern _preparse_pattern_; + private static final String PRE_PARSE_REGEX = + "(.*);([0-9]+)\\s*.*"; + + /** + * Constructor for a VMSFTPEntryParser object. Sets the versioning member + * to the supplied value. + * + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + */ + public VMSVersioningFTPEntryParser() + { + this(null); + } + + /** + * This constructor allows the creation of a VMSVersioningFTPEntryParser + * object with something other than the default configuration. + * + * @param config The {@link FTPClientConfig configuration} object used to + * configure this parser. + * @exception IllegalArgumentException + * Thrown if the regular expression is unparseable. Should not be seen + * under normal conditions. It it is seen, this is a sign that + * REGEX is not a valid regular expression. + * @since 1.4 + */ + public VMSVersioningFTPEntryParser(FTPClientConfig config) + { + super(); + configure(config); + try + { + //_preparse_matcher_ = new Perl5Matcher(); + _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); + } + catch (PatternSyntaxException pse) + { + throw new IllegalArgumentException ( + "Unparseable regex supplied: " + PRE_PARSE_REGEX); + } + + } + + + + private static class NameVersion { + String name; + int versionNumber; + NameVersion(String name, String vers) { + this.name = name; + this.versionNumber = Integer.parseInt(vers); + } + } + + /** + * Implement hook provided for those implementers (such as + * VMSVersioningFTPEntryParser, and possibly others) which return + * multiple files with the same name to remove the duplicates .. + * + * @param original Original list + * + * @return Original list purged of duplicates + */ + @Override + public List preParse(List original) { + original = super.preParse(original); + HashMap existingEntries = new HashMap(); + ListIterator iter = original.listIterator(); + while (iter.hasNext()) { + String entry = iter.next().trim(); + MatchResult result = null; + _preparse_matcher_ = _preparse_pattern_.matcher(entry); + if (_preparse_matcher_.matches()) { + result = _preparse_matcher_.toMatchResult(); + String name = result.group(1); + String version = result.group(2); + NameVersion nv = new NameVersion(name, version); + NameVersion existing = existingEntries.get(name); + if (null != existing) { + if (nv.versionNumber < existing.versionNumber) { + iter.remove(); // removal removes from original list. + continue; + } + } + existingEntries.put(name, nv); + } + + } + // we've now removed all entries less than with less than the largest + // version number for each name that were listed after the largest. + // we now must remove those with smaller than the largest version number + // for each name that were found before the largest + while (iter.hasPrevious()) { + String entry = iter.previous().trim(); + MatchResult result = null; + _preparse_matcher_ = _preparse_pattern_.matcher(entry); + if (_preparse_matcher_.matches()) { + result = _preparse_matcher_.toMatchResult(); + String name = result.group(1); + String version = result.group(2); + NameVersion nv = new NameVersion(name, version); + NameVersion existing = existingEntries.get(name); + if (null != existing) { + if (nv.versionNumber < existing.versionNumber) { + iter.remove(); // removal removes from original list. + } + } + } + + } + return original; + } + + + @Override + protected boolean isVersioning() { + return true; + } + +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/src/org/apache/commons/net/io/CopyStreamAdapter.java b/src/org/apache/commons/net/io/CopyStreamAdapter.java new file mode 100644 index 0000000..0679d23 --- /dev/null +++ b/src/org/apache/commons/net/io/CopyStreamAdapter.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.util.EventListener; + +import org.apache.commons.net.util.ListenerList; + +/** + * The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners + * when either of its bytesTransferred() methods are called. Its purpose + * is to facilitate the notification of the progress of a copy operation + * performed by one of the static copyStream() methods in + * org.apache.commons.io.Util to multiple listeners. The static + * copyStream() methods invoke the + * bytesTransfered(long, int) of a CopyStreamListener for performance + * reasons and also because multiple listeners cannot be registered given + * that the methods are static. + *

+ *

+ * @see CopyStreamEvent + * @see CopyStreamListener + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamAdapter.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public class CopyStreamAdapter implements CopyStreamListener +{ + private ListenerList internalListeners; + + /** + * Creates a new copyStreamAdapter. + */ + public CopyStreamAdapter() + { + internalListeners = new ListenerList(); + } + + /** + * This method is invoked by a CopyStreamEvent source after copying + * a block of bytes from a stream. The CopyStreamEvent will contain + * the total number of bytes transferred so far and the number of bytes + * transferred in the last write. The CopyStreamAdapater will relay + * the event to all of its registered listeners, listing itself as the + * source of the event. + * @param event The CopyStreamEvent fired by the copying of a block of + * bytes. + */ + public void bytesTransferred(CopyStreamEvent event) + { + bytesTransferred(event.getTotalBytesTransferred(), + event.getBytesTransferred(), + event.getStreamSize()); + } + + /** + * This method is not part of the JavaBeans model and is used by the + * static methods in the org.apache.commons.io.Util class for efficiency. + * It is invoked after a block of bytes to inform the listener of the + * transfer. The CopyStreamAdapater will create a CopyStreamEvent + * from the arguments and relay the event to all of its registered + * listeners, listing itself as the source of the event. + * @param totalBytesTransferred The total number of bytes transferred + * so far by the copy operation. + * @param bytesTransferred The number of bytes copied by the most recent + * write. + * @param streamSize The number of bytes in the stream being copied. + * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if + * the size is unknown. + */ + public void bytesTransferred(long totalBytesTransferred, + int bytesTransferred, long streamSize) + { + CopyStreamEvent event; + + event = new CopyStreamEvent(this, + totalBytesTransferred, + bytesTransferred, + streamSize); + + for (EventListener listener : internalListeners) + { + ((CopyStreamListener) (listener)).bytesTransferred(event); + } + } + + /** + * Registers a CopyStreamListener to receive CopyStreamEvents. + * Although this method is not declared to be synchronized, it is + * implemented in a thread safe manner. + * @param listener The CopyStreamlistener to register. + */ + public void addCopyStreamListener(CopyStreamListener listener) + { + internalListeners.addListener(listener); + } + + /** + * Unregisters a CopyStreamListener. Although this method is not + * synchronized, it is implemented in a thread safe manner. + * @param listener The CopyStreamlistener to unregister. + */ + public void removeCopyStreamListener(CopyStreamListener listener) + { + internalListeners.removeListener(listener); + } +} diff --git a/src/org/apache/commons/net/io/CopyStreamEvent.java b/src/org/apache/commons/net/io/CopyStreamEvent.java new file mode 100644 index 0000000..d7d0ec3 --- /dev/null +++ b/src/org/apache/commons/net/io/CopyStreamEvent.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.util.EventObject; + +/** + * A CopyStreamEvent is triggered after every write performed by a + * stream copying operation. The event stores the number of bytes + * transferred by the write triggering the event as well as the total + * number of bytes transferred so far by the copy operation. + *

+ *

+ * @see CopyStreamListener + * @see CopyStreamAdapter + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamEvent.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public class CopyStreamEvent extends EventObject +{ + /** + * Constant used to indicate the stream size is unknown. + */ + public static final long UNKNOWN_STREAM_SIZE = -1; + + private int bytesTransferred; + private long totalBytesTransferred; + private long streamSize; + + /** + * Creates a new CopyStreamEvent instance. + * @param source The source of the event. + * @param totalBytesTransferred The total number of bytes transferred so + * far during a copy operation. + * @param bytesTransferred The number of bytes transferred during the + * write that triggered the CopyStreamEvent. + * @param streamSize The number of bytes in the stream being copied. + * This may be set to UNKNOWN_STREAM_SIZE if the + * size is unknown. + */ + public CopyStreamEvent(Object source, long totalBytesTransferred, + int bytesTransferred, long streamSize) + { + super(source); + this.bytesTransferred = bytesTransferred; + this.totalBytesTransferred = totalBytesTransferred; + this.streamSize = streamSize; + } + + /** + * Returns the number of bytes transferred by the write that triggered + * the event. + * @return The number of bytes transferred by the write that triggered + * the vent. + */ + public int getBytesTransferred() + { + return bytesTransferred; + } + + /** + * Returns the total number of bytes transferred so far by the copy + * operation. + * @return The total number of bytes transferred so far by the copy + * operation. + */ + public long getTotalBytesTransferred() + { + return totalBytesTransferred; + } + + /** + * Returns the size of the stream being copied. + * This may be set to UNKNOWN_STREAM_SIZE if the + * size is unknown. + * @return The size of the stream being copied. + */ + public long getStreamSize() + { + return streamSize; + } +} diff --git a/src/org/apache/commons/net/io/CopyStreamException.java b/src/org/apache/commons/net/io/CopyStreamException.java new file mode 100644 index 0000000..8d34145 --- /dev/null +++ b/src/org/apache/commons/net/io/CopyStreamException.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; + +/** + * The CopyStreamException class is thrown by the org.apache.commons.io.Util + * copyStream() methods. It stores the number of bytes confirmed to + * have been transferred before an I/O error as well as the IOException + * responsible for the failure of a copy operation. + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamException.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public class CopyStreamException extends IOException +{ + private long totalBytesTransferred; + private IOException ioException; + + /** + * Creates a new CopyStreamException instance. + * @param message A message describing the error. + * @param bytesTransferred The total number of bytes transferred before + * an exception was thrown in a copy operation. + * @param exception The IOException thrown during a copy operation. + */ + public CopyStreamException(String message, + long bytesTransferred, + IOException exception) + { + super(message); + totalBytesTransferred = bytesTransferred; + ioException = exception; + } + + /** + * Returns the total number of bytes confirmed to have + * been transferred by a failed copy operation. + * @return The total number of bytes confirmed to have + * been transferred by a failed copy operation. + */ + public long getTotalBytesTransferred() + { + return totalBytesTransferred; + } + + /** + * Returns the IOException responsible for the failure of a copy operation. + * @return The IOException responsible for the failure of a copy operation. + */ + public IOException getIOException() + { + return ioException; + } +} diff --git a/src/org/apache/commons/net/io/CopyStreamListener.java b/src/org/apache/commons/net/io/CopyStreamListener.java new file mode 100644 index 0000000..9e97fb9 --- /dev/null +++ b/src/org/apache/commons/net/io/CopyStreamListener.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.util.EventListener; + +/** + * The CopyStreamListener class can accept CopyStreamEvents to keep track + * of the progress of a stream copying operation. However, it is currently + * not used that way within NetComponents for performance reasons. Rather + * the bytesTransferred(long, int) method is called directly rather than + * passing an event to bytesTransferred(CopyStreamEvent), saving the creation + * of a CopyStreamEvent instance. Also, the only place where + * CopyStreamListener is currently used within NetComponents is in the + * static methods of the uninstantiable org.apache.commons.io.Util class, which + * would preclude the use of addCopyStreamListener and + * removeCopyStreamListener methods. However, future additions may use the + * JavaBean event model, which is why the hooks have been included from the + * beginning. + *

+ *

+ * @see CopyStreamEvent + * @see CopyStreamAdapter + * @see Util + * @author Daniel F. Savarese + * @version $Id: CopyStreamListener.java 489397 2006-12-21 16:28:51Z rwinston $ + */ +public interface CopyStreamListener extends EventListener +{ + /** + * This method is invoked by a CopyStreamEvent source after copying + * a block of bytes from a stream. The CopyStreamEvent will contain + * the total number of bytes transferred so far and the number of bytes + * transferred in the last write. + * @param event The CopyStreamEvent fired by the copying of a block of + * bytes. + */ + public void bytesTransferred(CopyStreamEvent event); + + + /** + * This method is not part of the JavaBeans model and is used by the + * static methods in the org.apache.commons.io.Util class for efficiency. + * It is invoked after a block of bytes to inform the listener of the + * transfer. + * @param totalBytesTransferred The total number of bytes transferred + * so far by the copy operation. + * @param bytesTransferred The number of bytes copied by the most recent + * write. + * @param streamSize The number of bytes in the stream being copied. + * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if + * the size is unknown. + */ + public void bytesTransferred(long totalBytesTransferred, + int bytesTransferred, + long streamSize); +} diff --git a/src/org/apache/commons/net/io/DotTerminatedMessageReader.java b/src/org/apache/commons/net/io/DotTerminatedMessageReader.java new file mode 100644 index 0000000..c0f344d --- /dev/null +++ b/src/org/apache/commons/net/io/DotTerminatedMessageReader.java @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.PushbackReader; +import java.io.Reader; + +/** + * DotTerminatedMessageReader is a class used to read messages from a + * server that are terminated by a single dot followed by a + * <CR><LF> + * sequence and with double dots appearing at the begining of lines which + * do not signal end of message yet start with a dot. Various Internet + * protocols such as NNTP and POP3 produce messages of this type. + *

+ * This class handles stripping of the duplicate period at the beginning + * of lines starting with a period, converts NETASCII newlines to the + * local line separator format, truncates the end of message indicator, + * and ensures you cannot read past the end of the message. + * @author Daniel F. Savarese + * @version $Id: DotTerminatedMessageReader.java 636825 2008-03-13 18:34:52Z sebb $ + */ +public final class DotTerminatedMessageReader extends Reader +{ + private static final String LS; + private static final char[] LS_CHARS; + + static + { + LS = System.getProperty("line.separator"); + LS_CHARS = LS.toCharArray(); + } + + private boolean atBeginning; + private boolean eof; + private int pos; + private char[] internalBuffer; + private PushbackReader internalReader; + + /** + * Creates a DotTerminatedMessageReader that wraps an existing Reader + * input source. + * @param reader The Reader input source containing the message. + */ + public DotTerminatedMessageReader(Reader reader) + { + super(reader); + internalBuffer = new char[LS_CHARS.length + 3]; + pos = internalBuffer.length; + // Assumes input is at start of message + atBeginning = true; + eof = false; + internalReader = new PushbackReader(reader); + } + + /** + * Reads and returns the next character in the message. If the end of the + * message has been reached, returns -1. Note that a call to this method + * may result in multiple reads from the underlying input stream to decode + * the message properly (removing doubled dots and so on). All of + * this is transparent to the programmer and is only mentioned for + * completeness. + * @return The next character in the message. Returns -1 if the end of the + * message has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + */ + @Override + public int read() throws IOException + { + int ch; + + synchronized (lock) + { + if (pos < internalBuffer.length) + { + return internalBuffer[pos++]; + } + + if (eof) + { + return -1; + } + + if ((ch = internalReader.read()) == -1) + { + eof = true; + return -1; + } + + if (atBeginning) + { + atBeginning = false; + if (ch == '.') + { + ch = internalReader.read(); + + if (ch != '.') + { + // read newline + eof = true; + internalReader.read(); + return -1; + } + else + { + return '.'; + } + } + } + + if (ch == '\r') + { + ch = internalReader.read(); + + if (ch == '\n') + { + ch = internalReader.read(); + + if (ch == '.') + { + ch = internalReader.read(); + + if (ch != '.') + { + // read newline and indicate end of file + internalReader.read(); + eof = true; + } + else + { + internalBuffer[--pos] = (char) ch; + } + } + else + { + internalReader.unread(ch); + } + + pos -= LS_CHARS.length; + System.arraycopy(LS_CHARS, 0, internalBuffer, pos, + LS_CHARS.length); + ch = internalBuffer[pos++]; + } + else + { + internalBuffer[--pos] = (char) ch; + return '\r'; + } + } + + return ch; + } + } + + /** + * Reads the next characters from the message into an array and + * returns the number of characters read. Returns -1 if the end of the + * message has been reached. + * @param buffer The character array in which to store the characters. + * @return The number of characters read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + */ + @Override + public int read(char[] buffer) throws IOException + { + return read(buffer, 0, buffer.length); + } + + /** + * Reads the next characters from the message into an array and + * returns the number of characters read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + * @param buffer The character array in which to store the characters. + * @param offset The offset into the array at which to start storing + * characters. + * @param length The number of characters to read. + * @return The number of characters read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + */ + @Override + public int read(char[] buffer, int offset, int length) throws IOException + { + int ch, off; + synchronized (lock) + { + if (length < 1) + { + return 0; + } + if ((ch = read()) == -1) + { + return -1; + } + off = offset; + + do + { + buffer[offset++] = (char) ch; + } + while (--length > 0 && (ch = read()) != -1); + + return (offset - off); + } + } + + /** + * Determines if the message is ready to be read. + * @return True if the message is ready to be read, false if not. + * @exception IOException If an error occurs while checking the underlying + * stream. + */ + @Override + public boolean ready() throws IOException + { + synchronized (lock) + { + return (pos < internalBuffer.length || internalReader.ready()); + } + } + + /** + * Closes the message for reading. This doesn't actually close the + * underlying stream. The underlying stream may still be used for + * communicating with the server and therefore is not closed. + *

+ * If the end of the message has not yet been reached, this method + * will read the remainder of the message until it reaches the end, + * so that the underlying stream may continue to be used properly + * for communicating with the server. If you do not fully read + * a message, you MUST close it, otherwise your program will likely + * hang or behave improperly. + * @exception IOException If an error occurs while reading the + * underlying stream. + */ + @Override + public void close() throws IOException + { + synchronized (lock) + { + if (internalReader == null) + { + return; + } + + if (!eof) + { + while (read() != -1) + { + ; + } + } + eof = true; + atBeginning = false; + pos = internalBuffer.length; + internalReader = null; + } + } +} diff --git a/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java b/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java new file mode 100644 index 0000000..853e42f --- /dev/null +++ b/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.Writer; + +/*** + * DotTerminatedMessageWriter is a class used to write messages to a + * server that are terminated by a single dot followed by a + * <CR><LF> + * sequence and with double dots appearing at the begining of lines which + * do not signal end of message yet start with a dot. Various Internet + * protocols such as NNTP and POP3 produce messages of this type. + *

+ * This class handles the doubling of line-starting periods, + * converts single linefeeds to NETASCII newlines, and on closing + * will send the final message terminator dot and NETASCII newline + * sequence. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class DotTerminatedMessageWriter extends Writer +{ + private static final int __NOTHING_SPECIAL_STATE = 0; + private static final int __LAST_WAS_CR_STATE = 1; + private static final int __LAST_WAS_NL_STATE = 2; + + private int __state; + private Writer __output; + + + /*** + * Creates a DotTerminatedMessageWriter that wraps an existing Writer + * output destination. + *

+ * @param output The Writer output destination to write the message. + ***/ + public DotTerminatedMessageWriter(Writer output) + { + super(output); + __output = output; + __state = __NOTHING_SPECIAL_STATE; + } + + + /*** + * Writes a character to the output. Note that a call to this method + * may result in multiple writes to the underling Writer in order to + * convert naked linefeeds to NETASCII line separators and to double + * line-leading periods. This is transparent to the programmer and + * is only mentioned for completeness. + *

+ * @param ch The character to write. + * @exception IOException If an error occurs while writing to the + * underlying output. + ***/ + @Override + public void write(int ch) throws IOException + { + synchronized (lock) + { + switch (ch) + { + case '\r': + __state = __LAST_WAS_CR_STATE; + __output.write('\r'); + return ; + case '\n': + if (__state != __LAST_WAS_CR_STATE) + __output.write('\r'); + __output.write('\n'); + __state = __LAST_WAS_NL_STATE; + return ; + case '.': + // Double the dot at the beginning of a line + if (__state == __LAST_WAS_NL_STATE) + __output.write('.'); + // Fall through + default: + __state = __NOTHING_SPECIAL_STATE; + __output.write(ch); + return ; + } + } + } + + + /*** + * Writes a number of characters from a character array to the output + * starting from a given offset. + *

+ * @param buffer The character array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of characters to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(char[] buffer, int offset, int length) throws IOException + { + synchronized (lock) + { + while (length-- > 0) + write(buffer[offset++]); + } + } + + + /*** + * Writes a character array to the output. + *

+ * @param buffer The character array to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(char[] buffer) throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a String to the output. + *

+ * @param string The String to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(String string) throws IOException + { + write(string.toCharArray()); + } + + + /*** + * Writes part of a String to the output starting from a given offset. + *

+ * @param string The String to write. + * @param offset The offset into the String at which to start copying data. + * @param length The number of characters to write. + * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void write(String string, int offset, int length) throws IOException + { + write(string.toCharArray(), offset, length); + } + + + /*** + * Flushes the underlying output, writing all buffered output. + *

+ * @exception IOException If an error occurs while writing to the underlying + * output. + ***/ + @Override + public void flush() throws IOException + { + synchronized (lock) + { + __output.flush(); + } + } + + + /*** + * Flushes the underlying output, writing all buffered output, but doesn't + * actually close the underlying stream. The underlying stream may still + * be used for communicating with the server and therefore is not closed. + *

+ * @exception IOException If an error occurs while writing to the underlying + * output or closing the Writer. + ***/ + @Override + public void close() throws IOException + { + synchronized (lock) + { + if (__output == null) + return ; + + if (__state == __LAST_WAS_CR_STATE) + __output.write('\n'); + else if (__state != __LAST_WAS_NL_STATE) + __output.write("\r\n"); + + __output.write(".\r\n"); + + __output.flush(); + __output = null; + } + } + +} diff --git a/src/org/apache/commons/net/io/FromNetASCIIInputStream.java b/src/org/apache/commons/net/io/FromNetASCIIInputStream.java new file mode 100644 index 0000000..76588ab --- /dev/null +++ b/src/org/apache/commons/net/io/FromNetASCIIInputStream.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + +/*** + * This class wraps an input stream, replacing all occurrences + * of <CR><LF> (carriage return followed by a linefeed), + * which is the NETASCII standard for representing a newline, with the + * local line separator representation. You would use this class to + * implement ASCII file transfers requiring conversion from NETASCII. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FromNetASCIIInputStream extends PushbackInputStream +{ + static final boolean _noConversionRequired; + static final String _lineSeparator; + static final byte[] _lineSeparatorBytes; + + static { + _lineSeparator = System.getProperty("line.separator"); + _noConversionRequired = _lineSeparator.equals("\r\n"); + _lineSeparatorBytes = _lineSeparator.getBytes(); + } + + private int __length = 0; + + /*** + * Returns true if the NetASCII line separator differs from the system + * line separator, false if they are the same. This method is useful + * to determine whether or not you need to instantiate a + * FromNetASCIIInputStream object. + *

+ * @return True if the NETASCII line separator differs from the local + * system line separator, false if they are the same. + ***/ + public static final boolean isConversionRequired() + { + return !_noConversionRequired; + } + + /*** + * Creates a FromNetASCIIInputStream instance that wraps an existing + * InputStream. + ***/ + public FromNetASCIIInputStream(InputStream input) + { + super(input, _lineSeparatorBytes.length + 1); + } + + + private int __read() throws IOException + { + int ch; + + ch = super.read(); + + if (ch == '\r') + { + ch = super.read(); + if (ch == '\n') + { + unread(_lineSeparatorBytes); + ch = super.read(); + // This is a kluge for read(byte[], ...) to read the right amount + --__length; + } + else + { + if (ch != -1) + unread(ch); + return '\r'; + } + } + + return ch; + } + + + /*** + * Reads and returns the next byte in the stream. If the end of the + * message has been reached, returns -1. Note that a call to this method + * may result in multiple reads from the underlying input stream in order + * to convert NETASCII line separators to the local line separator format. + * This is transparent to the programmer and is only mentioned for + * completeness. + *

+ * @return The next character in the stream. Returns -1 if the end of the + * stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read() throws IOException + { + if (_noConversionRequired) + return super.read(); + + return __read(); + } + + + /*** + * Reads the next number of bytes from the stream into an array and + * returns the number of bytes read. Returns -1 if the end of the + * stream has been reached. + *

+ * @param buffer The byte array in which to store the data. + * @return The number of bytes read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[]) throws IOException + { + return read(buffer, 0, buffer.length); + } + + + /*** + * Reads the next number of bytes from the stream into an array and returns + * the number of bytes read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + *

+ * @param buffer The byte array in which to store the data. + * @param offset The offset into the array at which to start storing data. + * @param length The number of bytes to read. + * @return The number of bytes read. Returns -1 if the + * end of the stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[], int offset, int length) throws IOException + { + int ch, off; + + if (length < 1) + return 0; + + ch = available(); + + __length = (length > ch ? ch : length); + + // If nothing is available, block to read only one character + if (__length < 1) + __length = 1; + + if (_noConversionRequired) + return super.read(buffer, offset, __length); + + if ((ch = __read()) == -1) + return -1; + + off = offset; + + do + { + buffer[offset++] = (byte)ch; + } + while (--__length > 0 && (ch = __read()) != -1); + + + return (offset - off); + } + + + // PushbackInputStream in JDK 1.1.3 returns the wrong thing + /*** + * Returns the number of bytes that can be read without blocking EXCEPT + * when newline conversions have to be made somewhere within the + * available block of bytes. In other words, you really should not + * rely on the value returned by this method if you are trying to avoid + * blocking. + ***/ + @Override + public int available() throws IOException + { + return (buf.length - pos) + in.available(); + } + +} diff --git a/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java b/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java new file mode 100644 index 0000000..c025a1b --- /dev/null +++ b/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/*** + * This class wraps an output stream, replacing all occurrences + * of <CR><LF> (carriage return followed by a linefeed), + * which is the NETASCII standard for representing a newline, with the + * local line separator representation. You would use this class to + * implement ASCII file transfers requiring conversion from NETASCII. + *

+ * Because of the translation process, a call to flush() will + * not flush the last byte written if that byte was a carriage + * return. A call to {@link #close close() }, however, will + * flush the carriage return. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FromNetASCIIOutputStream extends FilterOutputStream +{ + private boolean __lastWasCR; + + /*** + * Creates a FromNetASCIIOutputStream instance that wraps an existing + * OutputStream. + *

+ * @param output The OutputStream to wrap. + ***/ + public FromNetASCIIOutputStream(OutputStream output) + { + super(output); + __lastWasCR = false; + } + + + private void __write(int ch) throws IOException + { + switch (ch) + { + case '\r': + __lastWasCR = true; + // Don't write anything. We need to see if next one is linefeed + break; + case '\n': + if (__lastWasCR) + { + out.write(FromNetASCIIInputStream._lineSeparatorBytes); + __lastWasCR = false; + break; + } + __lastWasCR = false; + out.write('\n'); + break; + default: + if (__lastWasCR) + { + out.write('\r'); + __lastWasCR = false; + } + out.write(ch); + break; + } + } + + + /*** + * Writes a byte to the stream. Note that a call to this method + * might not actually write a byte to the underlying stream until a + * subsequent character is written, from which it can be determined if + * a NETASCII line separator was encountered. + * This is transparent to the programmer and is only mentioned for + * completeness. + *

+ * @param ch The byte to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(int ch) + throws IOException + { + if (FromNetASCIIInputStream._noConversionRequired) + { + out.write(ch); + return ; + } + + __write(ch); + } + + + /*** + * Writes a byte array to the stream. + *

+ * @param buffer The byte array to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[]) + throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[], int offset, int length) + throws IOException + { + if (FromNetASCIIInputStream._noConversionRequired) + { + // FilterOutputStream method is very slow. + //super.write(buffer, offset, length); + out.write(buffer, offset, length); + return ; + } + + while (length-- > 0) + __write(buffer[offset++]); + } + + + /*** + * Closes the stream, writing all pending data. + *

+ * @exception IOException If an error occurs while closing the stream. + ***/ + @Override + public synchronized void close() + throws IOException + { + if (FromNetASCIIInputStream._noConversionRequired) + { + super.close(); + return ; + } + + if (__lastWasCR) + out.write('\r'); + super.close(); + } +} diff --git a/src/org/apache/commons/net/io/SocketInputStream.java b/src/org/apache/commons/net/io/SocketInputStream.java new file mode 100644 index 0000000..673f434 --- /dev/null +++ b/src/org/apache/commons/net/io/SocketInputStream.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; + +/*** + * This class wraps an input stream, storing a reference to its originating + * socket. When the stream is closed, it will also close the socket + * immediately afterward. This class is useful for situations where you + * are dealing with a stream originating from a socket, but do not have + * a reference to the socket, and want to make sure it closes when the + * stream closes. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketOutputStream + ***/ + +public class SocketInputStream extends FilterInputStream +{ + private Socket __socket; + + /*** + * Creates a SocketInputStream instance wrapping an input stream and + * storing a reference to a socket that should be closed on closing + * the stream. + *

+ * @param socket The socket to close on closing the stream. + * @param stream The input stream to wrap. + ***/ + public SocketInputStream(Socket socket, InputStream stream) + { + super(stream); + __socket = socket; + } + + /*** + * Closes the stream and immediately afterward closes the referenced + * socket. + *

+ * @exception IOException If there is an error in closing the stream + * or socket. + ***/ + @Override + public void close() throws IOException + { + super.close(); + __socket.close(); + } +} diff --git a/src/org/apache/commons/net/io/SocketOutputStream.java b/src/org/apache/commons/net/io/SocketOutputStream.java new file mode 100644 index 0000000..abd7f5d --- /dev/null +++ b/src/org/apache/commons/net/io/SocketOutputStream.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/*** + * This class wraps an output stream, storing a reference to its originating + * socket. When the stream is closed, it will also close the socket + * immediately afterward. This class is useful for situations where you + * are dealing with a stream originating from a socket, but do not have + * a reference to the socket, and want to make sure it closes when the + * stream closes. + *

+ *

+ * @author Daniel F. Savarese + * @see SocketInputStream + ***/ + +public class SocketOutputStream extends FilterOutputStream +{ + private Socket __socket; + + /*** + * Creates a SocketOutputStream instance wrapping an output stream and + * storing a reference to a socket that should be closed on closing + * the stream. + *

+ * @param socket The socket to close on closing the stream. + * @param stream The input stream to wrap. + ***/ + public SocketOutputStream(Socket socket, OutputStream stream) + { + super(stream); + __socket = socket; + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. This method bypasses the equivalent method in + * FilterOutputStream because the FilterOutputStream implementation is + * very inefficient. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(byte buffer[], int offset, int length) throws IOException + { + out.write(buffer, offset, length); + } + + + /*** + * Closes the stream and immediately afterward closes the referenced + * socket. + *

+ * @exception IOException If there is an error in closing the stream + * or socket. + ***/ + @Override + public void close() throws IOException + { + super.close(); + __socket.close(); + } +} diff --git a/src/org/apache/commons/net/io/ToNetASCIIInputStream.java b/src/org/apache/commons/net/io/ToNetASCIIInputStream.java new file mode 100644 index 0000000..55e4735 --- /dev/null +++ b/src/org/apache/commons/net/io/ToNetASCIIInputStream.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/*** + * This class wraps an input stream, replacing all singly occurring + * <LF> (linefeed) characters with <CR><LF> (carriage return + * followed by linefeed), which is the NETASCII standard for representing + * a newline. + * You would use this class to implement ASCII file transfers requiring + * conversion to NETASCII. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class ToNetASCIIInputStream extends FilterInputStream +{ + private static final int __NOTHING_SPECIAL = 0; + private static final int __LAST_WAS_CR = 1; + private static final int __LAST_WAS_NL = 2; + private int __status; + + /*** + * Creates a ToNetASCIIInputStream instance that wraps an existing + * InputStream. + *

+ * @param input The InputStream to . + ***/ + public ToNetASCIIInputStream(InputStream input) + { + super(input); + __status = __NOTHING_SPECIAL; + } + + + /*** + * Reads and returns the next byte in the stream. If the end of the + * message has been reached, returns -1. + *

+ * @return The next character in the stream. Returns -1 if the end of the + * stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read() throws IOException + { + int ch; + + if (__status == __LAST_WAS_NL) + { + __status = __NOTHING_SPECIAL; + return '\n'; + } + + ch = in.read(); + + switch (ch) + { + case '\r': + __status = __LAST_WAS_CR; + return '\r'; + case '\n': + if (__status != __LAST_WAS_CR) + { + __status = __LAST_WAS_NL; + return '\r'; + } + // else fall through + default: + __status = __NOTHING_SPECIAL; + return ch; + } + // statement not reached + //return ch; + } + + + /*** + * Reads the next number of bytes from the stream into an array and + * returns the number of bytes read. Returns -1 if the end of the + * stream has been reached. + *

+ * @param buffer The byte array in which to store the data. + * @return The number of bytes read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[]) throws IOException + { + return read(buffer, 0, buffer.length); + } + + + /*** + * Reads the next number of bytes from the stream into an array and returns + * the number of bytes read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + *

+ * @param buffer The byte array in which to store the data. + * @param offset The offset into the array at which to start storing data. + * @param length The number of bytes to read. + * @return The number of bytes read. Returns -1 if the + * end of the stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[], int offset, int length) throws IOException + { + int ch, off; + + if (length < 1) + return 0; + + ch = available(); + + if (length > ch) + length = ch; + + // If nothing is available, block to read only one character + if (length < 1) + length = 1; + + if ((ch = read()) == -1) + return -1; + + off = offset; + + do + { + buffer[offset++] = (byte)ch; + } + while (--length > 0 && (ch = read()) != -1); + + return (offset - off); + } + + /*** Returns false. Mark is not supported. ***/ + @Override + public boolean markSupported() + { + return false; + } + + @Override + public int available() throws IOException + { + int result; + + result = in.available(); + + if (__status == __LAST_WAS_NL) + return (result + 1); + + return result; + } +} diff --git a/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java b/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java new file mode 100644 index 0000000..aeacc98 --- /dev/null +++ b/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/*** + * This class wraps an output stream, replacing all singly occurring + * <LF> (linefeed) characters with <CR><LF> (carriage return + * followed by linefeed), which is the NETASCII standard for representing + * a newline. + * You would use this class to implement ASCII file transfers requiring + * conversion to NETASCII. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class ToNetASCIIOutputStream extends FilterOutputStream +{ + private boolean __lastWasCR; + + /*** + * Creates a ToNetASCIIOutputStream instance that wraps an existing + * OutputStream. + *

+ * @param output The OutputStream to wrap. + ***/ + public ToNetASCIIOutputStream(OutputStream output) + { + super(output); + __lastWasCR = false; + } + + + /*** + * Writes a byte to the stream. Note that a call to this method + * may result in multiple writes to the underlying input stream in order + * to convert naked newlines to NETASCII line separators. + * This is transparent to the programmer and is only mentioned for + * completeness. + *

+ * @param ch The byte to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(int ch) + throws IOException + { + switch (ch) + { + case '\r': + __lastWasCR = true; + out.write('\r'); + return ; + case '\n': + if (!__lastWasCR) + out.write('\r'); + // Fall through + default: + __lastWasCR = false; + out.write(ch); + return ; + } + } + + + /*** + * Writes a byte array to the stream. + *

+ * @param buffer The byte array to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[]) + throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public synchronized void write(byte buffer[], int offset, int length) + throws IOException + { + while (length-- > 0) + write(buffer[offset++]); + } + +} diff --git a/src/org/apache/commons/net/io/Util.java b/src/org/apache/commons/net/io/Util.java new file mode 100644 index 0000000..4e85a93 --- /dev/null +++ b/src/org/apache/commons/net/io/Util.java @@ -0,0 +1,334 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/*** + * The Util class cannot be instantiated and stores short static convenience + * methods that are often quite useful. + *

+ *

+ * @see CopyStreamException + * @see CopyStreamListener + * @see CopyStreamAdapter + * @author Daniel F. Savarese + ***/ + +public final class Util +{ + /*** + * The default buffer size used by {@link #copyStream copyStream } + * and {@link #copyReader copyReader }. It's value is 1024. + ***/ + public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; + + // Cannot be instantiated + private Util() + { } + + + /*** + * Copies the contents of an InputStream to an OutputStream using a + * copy buffer of a given size and notifies the provided + * CopyStreamListener of the progress of the copy operation by calling + * its bytesTransferred(long, int) method after each write to the + * destination. If you wish to notify more than one listener you should + * use a CopyStreamAdapter as the listener and register the additional + * listeners with the CopyStreamAdapter. + *

+ * The contents of the InputStream are + * read until the end of the stream is reached, but neither the + * source nor the destination are closed. You must do this yourself + * outside of the method call. The number of bytes read/written is + * returned. + *

+ * @param source The source InputStream. + * @param dest The destination OutputStream. + * @param bufferSize The number of bytes to buffer during the copy. + * @param streamSize The number of bytes in the stream being copied. + * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. + * @param listener The CopyStreamListener to notify of progress. If + * this parameter is null, notification is not attempted. + * @param flush Whether to flush the output stream after every + * write. This is necessary for interactive sessions that rely on + * buffered streams. If you don't flush, the data will stay in + * the stream buffer. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyStream(InputStream source, OutputStream dest, + int bufferSize, long streamSize, + CopyStreamListener listener, + boolean flush) + throws CopyStreamException + { + int bytes; + long total; + byte[] buffer; + + buffer = new byte[bufferSize]; + total = 0; + + try + { + while ((bytes = source.read(buffer)) != -1) + { + // Technically, some read(byte[]) methods may return 0 and we cannot + // accept that as an indication of EOF. + + if (bytes == 0) + { + bytes = source.read(); + if (bytes < 0) + break; + dest.write(bytes); + if(flush) + dest.flush(); + ++total; + if (listener != null) + listener.bytesTransferred(total, 1, streamSize); + continue; + } + + dest.write(buffer, 0, bytes); + if(flush) + dest.flush(); + total += bytes; + if (listener != null) + listener.bytesTransferred(total, bytes, streamSize); + } + } + catch (IOException e) + { + throw new CopyStreamException("IOException caught while copying.", + total, e); + } + + return total; + } + + + /*** + * Copies the contents of an InputStream to an OutputStream using a + * copy buffer of a given size and notifies the provided + * CopyStreamListener of the progress of the copy operation by calling + * its bytesTransferred(long, int) method after each write to the + * destination. If you wish to notify more than one listener you should + * use a CopyStreamAdapter as the listener and register the additional + * listeners with the CopyStreamAdapter. + *

+ * The contents of the InputStream are + * read until the end of the stream is reached, but neither the + * source nor the destination are closed. You must do this yourself + * outside of the method call. The number of bytes read/written is + * returned. + *

+ * @param source The source InputStream. + * @param dest The destination OutputStream. + * @param bufferSize The number of bytes to buffer during the copy. + * @param streamSize The number of bytes in the stream being copied. + * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. + * @param listener The CopyStreamListener to notify of progress. If + * this parameter is null, notification is not attempted. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyStream(InputStream source, OutputStream dest, + int bufferSize, long streamSize, + CopyStreamListener listener) + throws CopyStreamException + { + return copyStream(source, dest, bufferSize, streamSize, listener, + true); + } + + + /*** + * Copies the contents of an InputStream to an OutputStream using a + * copy buffer of a given size. The contents of the InputStream are + * read until the end of the stream is reached, but neither the + * source nor the destination are closed. You must do this yourself + * outside of the method call. The number of bytes read/written is + * returned. + *

+ * @param source The source InputStream. + * @param dest The destination OutputStream. + * @return The number of bytes read/written in the copy operation. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyStream(InputStream source, OutputStream dest, + int bufferSize) + throws CopyStreamException + { + return copyStream(source, dest, bufferSize, + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); + } + + + /*** + * Same as copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); + ***/ + public static final long copyStream(InputStream source, OutputStream dest) + throws CopyStreamException + { + return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); + } + + + /*** + * Copies the contents of a Reader to a Writer using a + * copy buffer of a given size and notifies the provided + * CopyStreamListener of the progress of the copy operation by calling + * its bytesTransferred(long, int) method after each write to the + * destination. If you wish to notify more than one listener you should + * use a CopyStreamAdapter as the listener and register the additional + * listeners with the CopyStreamAdapter. + *

+ * The contents of the Reader are + * read until its end is reached, but neither the source nor the + * destination are closed. You must do this yourself outside of the + * method call. The number of characters read/written is returned. + *

+ * @param source The source Reader. + * @param dest The destination writer. + * @param bufferSize The number of characters to buffer during the copy. + * @param streamSize The number of characters in the stream being copied. + * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. + * @param listener The CopyStreamListener to notify of progress. If + * this parameter is null, notification is not attempted. + * @return The number of characters read/written in the copy operation. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyReader(Reader source, Writer dest, + int bufferSize, long streamSize, + CopyStreamListener listener) + throws CopyStreamException + { + int chars; + long total; + char[] buffer; + + buffer = new char[bufferSize]; + total = 0; + + try + { + while ((chars = source.read(buffer)) != -1) + { + // Technically, some read(char[]) methods may return 0 and we cannot + // accept that as an indication of EOF. + if (chars == 0) + { + chars = source.read(); + if (chars < 0) + break; + dest.write(chars); + dest.flush(); + ++total; + if (listener != null) + listener.bytesTransferred(total, chars, streamSize); + continue; + } + + dest.write(buffer, 0, chars); + dest.flush(); + total += chars; + if (listener != null) + listener.bytesTransferred(total, chars, streamSize); + } + } + catch (IOException e) + { + throw new CopyStreamException("IOException caught while copying.", + total, e); + } + + return total; + } + + + /*** + * Copies the contents of a Reader to a Writer using a + * copy buffer of a given size. The contents of the Reader are + * read until its end is reached, but neither the source nor the + * destination are closed. You must do this yourself outside of the + * method call. The number of characters read/written is returned. + *

+ * @param source The source Reader. + * @param dest The destination writer. + * @param bufferSize The number of characters to buffer during the copy. + * @return The number of characters read/written in the copy operation. + * @exception CopyStreamException If an error occurs while reading from the + * source or writing to the destination. The CopyStreamException + * will contain the number of bytes confirmed to have been + * transferred before an + * IOException occurred, and it will also contain the IOException + * that caused the error. These values can be retrieved with + * the CopyStreamException getTotalBytesTransferred() and + * getIOException() methods. + ***/ + public static final long copyReader(Reader source, Writer dest, + int bufferSize) + throws CopyStreamException + { + return copyReader(source, dest, bufferSize, + CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); + } + + + /*** + * Same as copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); + ***/ + public static final long copyReader(Reader source, Writer dest) + throws CopyStreamException + { + return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); + } + +} diff --git a/src/org/apache/commons/net/util/ListenerList.java b/src/org/apache/commons/net/util/ListenerList.java new file mode 100644 index 0000000..796fb78 --- /dev/null +++ b/src/org/apache/commons/net/util/ListenerList.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.util; + +import java.io.Serializable; +import java.util.EventListener; +import java.util.Iterator; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author Daniel F. Savarese + */ + +public class ListenerList implements Serializable, Iterable +{ + private final CopyOnWriteArrayList __listeners; + + public ListenerList() + { + __listeners = new CopyOnWriteArrayList(); + } + + public void addListener(EventListener listener) + { + __listeners.add(listener); + } + + public void removeListener(EventListener listener) + { + __listeners.remove(listener); + } + + public int getListenerCount() + { + return __listeners.size(); + } + + /** + * Return an {@link Iterator} for the {@link EventListener} instances + * + * @since 2.0 + * TODO Check that this is a good defensive strategy + */ + public Iterator iterator() { + return __listeners.iterator(); + } + +} diff --git a/src/org/apache/commons/net/util/SubnetUtils.java b/src/org/apache/commons/net/util/SubnetUtils.java new file mode 100644 index 0000000..90cc6e8 --- /dev/null +++ b/src/org/apache/commons/net/util/SubnetUtils.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.net.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A class that performs some subnet calculations given a network address and a subnet mask. + * @see http://www.faqs.org/rfcs/rfc1519.html + * @author + * @since 2.0 + */ +public class SubnetUtils { + + private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"; + private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,3})"; + private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS); + private static final Pattern cidrPattern = Pattern.compile(SLASH_FORMAT); + private static final int NBITS = 32; + + private int netmask = 0; + private int address = 0; + private int network = 0; + private int broadcast = 0; + + /** + * Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" + * @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16" + */ + public SubnetUtils(String cidrNotation) { + calculate(cidrNotation); + } + + /** + * Constructor that takes two dotted decimal addresses. + * @param address An IP address, e.g. "192.168.0.1" + * @param mask A dotted decimal netmask e.g. "255.255.0.0" + */ + public SubnetUtils(String address, String mask) { + calculate(toCidrNotation(address, mask)); + } + + /** + * Convenience container for subnet summary information. + * + */ + public final class SubnetInfo { + private SubnetInfo() {} + + private int netmask() { return netmask; } + private int network() { return network; } + private int address() { return address; } + private int broadcast() { return broadcast; } + private int low() { return network() + 1; } + private int high() { return broadcast() - 1; } + + public boolean isInRange(String address) { return isInRange(toInteger(address)); } + private boolean isInRange(int address) { return ((address-low()) <= (high()-low())); } + + public String getBroadcastAddress() { return format(toArray(broadcast())); } + public String getNetworkAddress() { return format(toArray(network())); } + public String getNetmask() { return format(toArray(netmask())); } + public String getAddress() { return format(toArray(address())); } + public String getLowAddress() { return format(toArray(low())); } + public String getHighAddress() { return format(toArray(high())); } + public int getAddressCount() { return (broadcast() - low()); } + + public int asInteger(String address) { return toInteger(address); } + + public String getCidrSignature() { + return toCidrNotation( + format(toArray(address())), + format(toArray(netmask())) + ); + } + + public String[] getAllAddresses() { + String[] addresses = new String[getAddressCount()]; + for (int add = low(), j=0; add <= high(); ++add, ++j) { + addresses[j] = format(toArray(add)); + } + return addresses; + } + } + + /** + * Return a {@link SubnetInfo} instance that contains subnet-specific statistics + * @return + */ + public final SubnetInfo getInfo() { return new SubnetInfo(); } + + /* + * Initialize the internal fields from the supplied CIDR mask + */ + private void calculate(String mask) { + Matcher matcher = cidrPattern.matcher(mask); + + if (matcher.matches()) { + address = matchAddress(matcher); + + /* Create a binary netmask from the number of bits specification /x */ + int cidrPart = rangeCheck(Integer.parseInt(matcher.group(5)), 0, NBITS-1); + for (int j = 0; j < cidrPart; ++j) { + netmask |= (1 << 31-j); + } + + /* Calculate base network address */ + network = (address & netmask); + + /* Calculate broadcast address */ + broadcast = network | ~(netmask); + } + else + throw new IllegalArgumentException("Could not parse [" + mask + "]"); + } + + /* + * Convert a dotted decimal format address to a packed integer format + */ + private int toInteger(String address) { + Matcher matcher = addressPattern.matcher(address); + if (matcher.matches()) { + return matchAddress(matcher); + } + else + throw new IllegalArgumentException("Could not parse [" + address + "]"); + } + + /* + * Convenience method to extract the components of a dotted decimal address and + * pack into an integer using a regex match + */ + private int matchAddress(Matcher matcher) { + int addr = 0; + for (int i = 1; i <= 4; ++i) { + int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255)); + addr |= ((n & 0xff) << 8*(4-i)); + } + return addr; + } + + /* + * Convert a packed integer address into a 4-element array + */ + private int[] toArray(int val) { + int ret[] = new int[4]; + for (int j = 3; j >= 0; --j) + ret[j] |= ((val >>> 8*(3-j)) & (0xff)); + return ret; + } + + /* + * Convert a 4-element array into dotted decimal format + */ + private String format(int[] octets) { + StringBuilder str = new StringBuilder(); + for (int i =0; i < octets.length; ++i){ + str.append(octets[i]); + if (i != octets.length - 1) { + str.append("."); + } + } + return str.toString(); + } + + /* + * Convenience function to check integer boundaries + */ + private int rangeCheck(int value, int begin, int end) { + if (value >= begin && value <= end) + return value; + + throw new IllegalArgumentException("Value out of range: [" + value + "]"); + } + + /* + * Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy + * see Hacker's Delight section 5.1 + */ + int pop(int x) { + x = x - ((x >>> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); + x = (x + (x >>> 4)) & 0x0F0F0F0F; + x = x + (x >>> 8); + x = x + (x >>> 16); + return x & 0x0000003F; + } + + /* Convert two dotted decimal addresses to a single xxx.xxx.xxx.xxx/yy format + * by counting the 1-bit population in the mask address. (It may be better to count + * NBITS-#trailing zeroes for this case) + */ + private String toCidrNotation(String addr, String mask) { + return addr + "/" + pop(toInteger(mask)); + } +} -- cgit v1.2.3 From bbbc051aa70b8c3dc98218b7b7ca23bea588f41a Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 17:16:37 +0100 Subject: Removed duplicate org.apache.commons files --- org/apache/commons/net/DatagramSocketClient.java | 275 --- org/apache/commons/net/DatagramSocketFactory.java | 67 - .../commons/net/DefaultDatagramSocketFactory.java | 75 - org/apache/commons/net/DefaultSocketFactory.java | 165 -- .../net/MalformedServerReplyException.class | Bin 344 -> 0 bytes .../commons/net/MalformedServerReplyException.java | 55 - org/apache/commons/net/PrintCommandListener.java | 54 - org/apache/commons/net/ProtocolCommandEvent.class | Bin 999 -> 0 bytes org/apache/commons/net/ProtocolCommandEvent.java | 146 -- .../commons/net/ProtocolCommandListener.class | Bin 294 -> 0 bytes .../commons/net/ProtocolCommandListener.java | 59 - .../commons/net/ProtocolCommandSupport.class | Bin 1772 -> 0 bytes org/apache/commons/net/ProtocolCommandSupport.java | 134 -- org/apache/commons/net/SocketClient.class | Bin 4744 -> 0 bytes org/apache/commons/net/SocketClient.java | 586 ----- org/apache/commons/net/bsd/RCommandClient.java | 402 ---- org/apache/commons/net/bsd/RExecClient.java | 292 --- org/apache/commons/net/bsd/RLoginClient.java | 131 -- .../commons/net/chargen/CharGenTCPClient.java | 86 - .../commons/net/chargen/CharGenUDPClient.java | 129 -- .../commons/net/daytime/DaytimeTCPClient.java | 92 - .../commons/net/daytime/DaytimeUDPClient.java | 84 - .../commons/net/discard/DiscardTCPClient.java | 67 - .../commons/net/discard/DiscardUDPClient.java | 97 - org/apache/commons/net/echo/EchoTCPClient.java | 72 - org/apache/commons/net/echo/EchoUDPClient.java | 101 - org/apache/commons/net/finger/FingerClient.java | 197 -- org/apache/commons/net/ftp/Configurable.class | Bin 202 -> 0 bytes org/apache/commons/net/ftp/Configurable.java | 35 - org/apache/commons/net/ftp/FTP.class | Bin 9922 -> 0 bytes org/apache/commons/net/ftp/FTP.java | 1513 ------------ org/apache/commons/net/ftp/FTPClient.class | Bin 16187 -> 0 bytes org/apache/commons/net/ftp/FTPClient.java | 2447 -------------------- org/apache/commons/net/ftp/FTPClientConfig.class | Bin 4524 -> 0 bytes org/apache/commons/net/ftp/FTPClientConfig.java | 580 ----- org/apache/commons/net/ftp/FTPCommand.class | Bin 2624 -> 0 bytes org/apache/commons/net/ftp/FTPCommand.java | 131 -- .../net/ftp/FTPConnectionClosedException.class | Bin 346 -> 0 bytes .../net/ftp/FTPConnectionClosedException.java | 55 - org/apache/commons/net/ftp/FTPFile.class | Bin 2732 -> 0 bytes org/apache/commons/net/ftp/FTPFile.java | 392 ---- .../commons/net/ftp/FTPFileEntryParser.class | Bin 499 -> 0 bytes org/apache/commons/net/ftp/FTPFileEntryParser.java | 152 -- .../commons/net/ftp/FTPFileEntryParserImpl.class | Bin 1098 -> 0 bytes .../commons/net/ftp/FTPFileEntryParserImpl.java | 85 - .../commons/net/ftp/FTPListParseEngine.class | Bin 2970 -> 0 bytes org/apache/commons/net/ftp/FTPListParseEngine.java | 290 --- org/apache/commons/net/ftp/FTPReply.class | Bin 4171 -> 0 bytes org/apache/commons/net/ftp/FTPReply.java | 240 -- org/apache/commons/net/ftp/FTPSClient.java | 533 ----- org/apache/commons/net/ftp/FTPSCommand.java | 50 - org/apache/commons/net/ftp/FTPSSocketFactory.java | 82 - org/apache/commons/net/ftp/FTPSTrustManager.java | 54 - .../net/ftp/parser/CompositeFileEntryParser.class | Bin 882 -> 0 bytes .../net/ftp/parser/CompositeFileEntryParser.java | 72 - .../ConfigurableFTPFileEntryParserImpl.class | Bin 1378 -> 0 bytes .../parser/ConfigurableFTPFileEntryParserImpl.java | 116 - .../parser/DefaultFTPFileEntryParserFactory.class | Bin 4098 -> 0 bytes .../parser/DefaultFTPFileEntryParserFactory.java | 247 -- .../ftp/parser/EnterpriseUnixFTPEntryParser.java | 166 -- .../net/ftp/parser/FTPFileEntryParserFactory.class | Bin 473 -> 0 bytes .../net/ftp/parser/FTPFileEntryParserFactory.java | 68 - .../net/ftp/parser/FTPTimestampParser.class | Bin 409 -> 0 bytes .../commons/net/ftp/parser/FTPTimestampParser.java | 52 - .../net/ftp/parser/FTPTimestampParserImpl.class | Bin 4464 -> 0 bytes .../net/ftp/parser/FTPTimestampParserImpl.java | 301 --- .../commons/net/ftp/parser/MVSFTPEntryParser.class | Bin 4638 -> 0 bytes .../commons/net/ftp/parser/MVSFTPEntryParser.java | 495 ---- .../commons/net/ftp/parser/NTFTPEntryParser.class | Bin 2100 -> 0 bytes .../commons/net/ftp/parser/NTFTPEntryParser.java | 147 -- .../net/ftp/parser/NetwareFTPEntryParser.class | Bin 2169 -> 0 bytes .../net/ftp/parser/NetwareFTPEntryParser.java | 176 -- .../commons/net/ftp/parser/OS2FTPEntryParser.class | Bin 2062 -> 0 bytes .../commons/net/ftp/parser/OS2FTPEntryParser.java | 147 -- .../net/ftp/parser/OS400FTPEntryParser.class | Bin 2427 -> 0 bytes .../net/ftp/parser/OS400FTPEntryParser.java | 158 -- .../ftp/parser/ParserInitializationException.class | Bin 548 -> 0 bytes .../ftp/parser/ParserInitializationException.java | 65 - .../ftp/parser/RegexFTPFileEntryParserImpl.class | Bin 2082 -> 0 bytes .../ftp/parser/RegexFTPFileEntryParserImpl.java | 155 -- .../net/ftp/parser/UnixFTPEntryParser.class | Bin 3748 -> 0 bytes .../commons/net/ftp/parser/UnixFTPEntryParser.java | 295 --- .../commons/net/ftp/parser/VMSFTPEntryParser.class | Bin 4251 -> 0 bytes .../commons/net/ftp/parser/VMSFTPEntryParser.java | 288 --- .../VMSVersioningFTPEntryParser$NameVersion.class | Bin 605 -> 0 bytes .../ftp/parser/VMSVersioningFTPEntryParser.class | Bin 2768 -> 0 bytes .../ftp/parser/VMSVersioningFTPEntryParser.java | 183 -- org/apache/commons/net/io/CopyStreamAdapter.java | 122 - org/apache/commons/net/io/CopyStreamEvent.class | Bin 701 -> 0 bytes org/apache/commons/net/io/CopyStreamEvent.java | 98 - .../commons/net/io/CopyStreamException.class | Bin 593 -> 0 bytes org/apache/commons/net/io/CopyStreamException.java | 71 - org/apache/commons/net/io/CopyStreamListener.class | Bin 267 -> 0 bytes org/apache/commons/net/io/CopyStreamListener.java | 72 - .../commons/net/io/DotTerminatedMessageReader.java | 280 --- .../commons/net/io/DotTerminatedMessageWriter.java | 215 -- .../commons/net/io/FromNetASCIIInputStream.class | Bin 1844 -> 0 bytes .../commons/net/io/FromNetASCIIInputStream.java | 205 -- .../commons/net/io/FromNetASCIIOutputStream.java | 174 -- org/apache/commons/net/io/SocketInputStream.class | Bin 527 -> 0 bytes org/apache/commons/net/io/SocketInputStream.java | 69 - org/apache/commons/net/io/SocketOutputStream.class | Bin 690 -> 0 bytes org/apache/commons/net/io/SocketOutputStream.java | 89 - .../commons/net/io/ToNetASCIIInputStream.java | 181 -- .../commons/net/io/ToNetASCIIOutputStream.class | Bin 817 -> 0 bytes .../commons/net/io/ToNetASCIIOutputStream.java | 119 - org/apache/commons/net/io/Util.class | Bin 2431 -> 0 bytes org/apache/commons/net/io/Util.java | 334 --- org/apache/commons/net/nntp/Article.java | 253 -- org/apache/commons/net/nntp/ArticlePointer.java | 39 - org/apache/commons/net/nntp/NNTP.java | 1022 -------- org/apache/commons/net/nntp/NNTPClient.java | 1285 ---------- org/apache/commons/net/nntp/NNTPCommand.java | 83 - .../net/nntp/NNTPConnectionClosedException.java | 56 - org/apache/commons/net/nntp/NNTPReply.java | 209 -- .../commons/net/nntp/NewGroupsOrNewsQuery.java | 283 --- org/apache/commons/net/nntp/NewsgroupInfo.java | 155 -- org/apache/commons/net/nntp/SimpleNNTPHeader.java | 164 -- org/apache/commons/net/nntp/Threadable.java | 34 - org/apache/commons/net/nntp/Threader.java | 481 ---- org/apache/commons/net/ntp/NTPUDPClient.java | 140 -- org/apache/commons/net/ntp/NtpUtils.java | 113 - org/apache/commons/net/ntp/NtpV3Impl.java | 583 ----- org/apache/commons/net/ntp/NtpV3Packet.java | 236 -- org/apache/commons/net/ntp/TimeInfo.java | 295 --- org/apache/commons/net/ntp/TimeStamp.java | 490 ---- org/apache/commons/net/pop3/POP3.java | 358 --- org/apache/commons/net/pop3/POP3Client.java | 552 ----- org/apache/commons/net/pop3/POP3Command.java | 72 - org/apache/commons/net/pop3/POP3MessageInfo.java | 82 - org/apache/commons/net/pop3/POP3Reply.java | 38 - org/apache/commons/net/smtp/RelayPath.java | 102 - org/apache/commons/net/smtp/SMTP.java | 777 ------- org/apache/commons/net/smtp/SMTPClient.java | 607 ----- org/apache/commons/net/smtp/SMTPCommand.java | 91 - .../net/smtp/SMTPConnectionClosedException.java | 56 - org/apache/commons/net/smtp/SMTPReply.java | 167 -- org/apache/commons/net/smtp/SimpleSMTPHeader.java | 153 -- .../commons/net/telnet/EchoOptionHandler.java | 90 - .../net/telnet/InvalidTelnetOptionException.java | 62 - .../commons/net/telnet/SimpleOptionHandler.java | 96 - .../net/telnet/SuppressGAOptionHandler.java | 89 - org/apache/commons/net/telnet/Telnet.java | 1317 ----------- org/apache/commons/net/telnet/TelnetClient.java | 306 --- org/apache/commons/net/telnet/TelnetCommand.java | 132 -- .../commons/net/telnet/TelnetInputStream.java | 630 ----- .../net/telnet/TelnetNotificationHandler.java | 66 - org/apache/commons/net/telnet/TelnetOption.java | 193 -- .../commons/net/telnet/TelnetOptionHandler.java | 272 --- .../commons/net/telnet/TelnetOutputStream.java | 152 -- .../net/telnet/TerminalTypeOptionHandler.java | 136 -- .../net/telnet/WindowSizeOptionHandler.java | 188 -- org/apache/commons/net/tftp/TFTP.java | 301 --- org/apache/commons/net/tftp/TFTPAckPacket.java | 158 -- org/apache/commons/net/tftp/TFTPClient.java | 610 ----- org/apache/commons/net/tftp/TFTPDataPacket.java | 254 -- org/apache/commons/net/tftp/TFTPErrorPacket.java | 226 -- org/apache/commons/net/tftp/TFTPPacket.java | 247 -- .../commons/net/tftp/TFTPPacketException.java | 57 - .../commons/net/tftp/TFTPReadRequestPacket.java | 80 - org/apache/commons/net/tftp/TFTPRequestPacket.java | 253 -- .../commons/net/tftp/TFTPWriteRequestPacket.java | 79 - org/apache/commons/net/time/TimeTCPClient.java | 109 - org/apache/commons/net/time/TimeUDPClient.java | 127 - org/apache/commons/net/util/ListenerList.class | Bin 1085 -> 0 bytes org/apache/commons/net/util/ListenerList.java | 63 - org/apache/commons/net/util/SubnetUtils.java | 211 -- org/apache/commons/net/whois/WhoisClient.java | 109 - 168 files changed, 30754 deletions(-) delete mode 100644 org/apache/commons/net/DatagramSocketClient.java delete mode 100644 org/apache/commons/net/DatagramSocketFactory.java delete mode 100644 org/apache/commons/net/DefaultDatagramSocketFactory.java delete mode 100644 org/apache/commons/net/DefaultSocketFactory.java delete mode 100644 org/apache/commons/net/MalformedServerReplyException.class delete mode 100644 org/apache/commons/net/MalformedServerReplyException.java delete mode 100644 org/apache/commons/net/PrintCommandListener.java delete mode 100644 org/apache/commons/net/ProtocolCommandEvent.class delete mode 100644 org/apache/commons/net/ProtocolCommandEvent.java delete mode 100644 org/apache/commons/net/ProtocolCommandListener.class delete mode 100644 org/apache/commons/net/ProtocolCommandListener.java delete mode 100644 org/apache/commons/net/ProtocolCommandSupport.class delete mode 100644 org/apache/commons/net/ProtocolCommandSupport.java delete mode 100644 org/apache/commons/net/SocketClient.class delete mode 100644 org/apache/commons/net/SocketClient.java delete mode 100644 org/apache/commons/net/bsd/RCommandClient.java delete mode 100644 org/apache/commons/net/bsd/RExecClient.java delete mode 100644 org/apache/commons/net/bsd/RLoginClient.java delete mode 100644 org/apache/commons/net/chargen/CharGenTCPClient.java delete mode 100644 org/apache/commons/net/chargen/CharGenUDPClient.java delete mode 100644 org/apache/commons/net/daytime/DaytimeTCPClient.java delete mode 100644 org/apache/commons/net/daytime/DaytimeUDPClient.java delete mode 100644 org/apache/commons/net/discard/DiscardTCPClient.java delete mode 100644 org/apache/commons/net/discard/DiscardUDPClient.java delete mode 100644 org/apache/commons/net/echo/EchoTCPClient.java delete mode 100644 org/apache/commons/net/echo/EchoUDPClient.java delete mode 100644 org/apache/commons/net/finger/FingerClient.java delete mode 100644 org/apache/commons/net/ftp/Configurable.class delete mode 100644 org/apache/commons/net/ftp/Configurable.java delete mode 100644 org/apache/commons/net/ftp/FTP.class delete mode 100644 org/apache/commons/net/ftp/FTP.java delete mode 100644 org/apache/commons/net/ftp/FTPClient.class delete mode 100644 org/apache/commons/net/ftp/FTPClient.java delete mode 100644 org/apache/commons/net/ftp/FTPClientConfig.class delete mode 100644 org/apache/commons/net/ftp/FTPClientConfig.java delete mode 100644 org/apache/commons/net/ftp/FTPCommand.class delete mode 100644 org/apache/commons/net/ftp/FTPCommand.java delete mode 100644 org/apache/commons/net/ftp/FTPConnectionClosedException.class delete mode 100644 org/apache/commons/net/ftp/FTPConnectionClosedException.java delete mode 100644 org/apache/commons/net/ftp/FTPFile.class delete mode 100644 org/apache/commons/net/ftp/FTPFile.java delete mode 100644 org/apache/commons/net/ftp/FTPFileEntryParser.class delete mode 100644 org/apache/commons/net/ftp/FTPFileEntryParser.java delete mode 100644 org/apache/commons/net/ftp/FTPFileEntryParserImpl.class delete mode 100644 org/apache/commons/net/ftp/FTPFileEntryParserImpl.java delete mode 100644 org/apache/commons/net/ftp/FTPListParseEngine.class delete mode 100644 org/apache/commons/net/ftp/FTPListParseEngine.java delete mode 100644 org/apache/commons/net/ftp/FTPReply.class delete mode 100644 org/apache/commons/net/ftp/FTPReply.java delete mode 100644 org/apache/commons/net/ftp/FTPSClient.java delete mode 100644 org/apache/commons/net/ftp/FTPSCommand.java delete mode 100644 org/apache/commons/net/ftp/FTPSSocketFactory.java delete mode 100644 org/apache/commons/net/ftp/FTPSTrustManager.java delete mode 100644 org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class delete mode 100644 org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java delete mode 100644 org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class delete mode 100644 org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java delete mode 100644 org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class delete mode 100644 org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java delete mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParser.class delete mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParser.java delete mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class delete mode 100644 org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java delete mode 100644 org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/NTFTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/NTFTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/ParserInitializationException.class delete mode 100644 org/apache/commons/net/ftp/parser/ParserInitializationException.java delete mode 100644 org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class delete mode 100644 org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java delete mode 100644 org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java delete mode 100644 org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class delete mode 100644 org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class delete mode 100644 org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java delete mode 100644 org/apache/commons/net/io/CopyStreamAdapter.java delete mode 100644 org/apache/commons/net/io/CopyStreamEvent.class delete mode 100644 org/apache/commons/net/io/CopyStreamEvent.java delete mode 100644 org/apache/commons/net/io/CopyStreamException.class delete mode 100644 org/apache/commons/net/io/CopyStreamException.java delete mode 100644 org/apache/commons/net/io/CopyStreamListener.class delete mode 100644 org/apache/commons/net/io/CopyStreamListener.java delete mode 100644 org/apache/commons/net/io/DotTerminatedMessageReader.java delete mode 100644 org/apache/commons/net/io/DotTerminatedMessageWriter.java delete mode 100644 org/apache/commons/net/io/FromNetASCIIInputStream.class delete mode 100644 org/apache/commons/net/io/FromNetASCIIInputStream.java delete mode 100644 org/apache/commons/net/io/FromNetASCIIOutputStream.java delete mode 100644 org/apache/commons/net/io/SocketInputStream.class delete mode 100644 org/apache/commons/net/io/SocketInputStream.java delete mode 100644 org/apache/commons/net/io/SocketOutputStream.class delete mode 100644 org/apache/commons/net/io/SocketOutputStream.java delete mode 100644 org/apache/commons/net/io/ToNetASCIIInputStream.java delete mode 100644 org/apache/commons/net/io/ToNetASCIIOutputStream.class delete mode 100644 org/apache/commons/net/io/ToNetASCIIOutputStream.java delete mode 100644 org/apache/commons/net/io/Util.class delete mode 100644 org/apache/commons/net/io/Util.java delete mode 100644 org/apache/commons/net/nntp/Article.java delete mode 100644 org/apache/commons/net/nntp/ArticlePointer.java delete mode 100644 org/apache/commons/net/nntp/NNTP.java delete mode 100644 org/apache/commons/net/nntp/NNTPClient.java delete mode 100644 org/apache/commons/net/nntp/NNTPCommand.java delete mode 100644 org/apache/commons/net/nntp/NNTPConnectionClosedException.java delete mode 100644 org/apache/commons/net/nntp/NNTPReply.java delete mode 100644 org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java delete mode 100644 org/apache/commons/net/nntp/NewsgroupInfo.java delete mode 100644 org/apache/commons/net/nntp/SimpleNNTPHeader.java delete mode 100644 org/apache/commons/net/nntp/Threadable.java delete mode 100644 org/apache/commons/net/nntp/Threader.java delete mode 100644 org/apache/commons/net/ntp/NTPUDPClient.java delete mode 100644 org/apache/commons/net/ntp/NtpUtils.java delete mode 100644 org/apache/commons/net/ntp/NtpV3Impl.java delete mode 100644 org/apache/commons/net/ntp/NtpV3Packet.java delete mode 100644 org/apache/commons/net/ntp/TimeInfo.java delete mode 100644 org/apache/commons/net/ntp/TimeStamp.java delete mode 100644 org/apache/commons/net/pop3/POP3.java delete mode 100644 org/apache/commons/net/pop3/POP3Client.java delete mode 100644 org/apache/commons/net/pop3/POP3Command.java delete mode 100644 org/apache/commons/net/pop3/POP3MessageInfo.java delete mode 100644 org/apache/commons/net/pop3/POP3Reply.java delete mode 100644 org/apache/commons/net/smtp/RelayPath.java delete mode 100644 org/apache/commons/net/smtp/SMTP.java delete mode 100644 org/apache/commons/net/smtp/SMTPClient.java delete mode 100644 org/apache/commons/net/smtp/SMTPCommand.java delete mode 100644 org/apache/commons/net/smtp/SMTPConnectionClosedException.java delete mode 100644 org/apache/commons/net/smtp/SMTPReply.java delete mode 100644 org/apache/commons/net/smtp/SimpleSMTPHeader.java delete mode 100644 org/apache/commons/net/telnet/EchoOptionHandler.java delete mode 100644 org/apache/commons/net/telnet/InvalidTelnetOptionException.java delete mode 100644 org/apache/commons/net/telnet/SimpleOptionHandler.java delete mode 100644 org/apache/commons/net/telnet/SuppressGAOptionHandler.java delete mode 100644 org/apache/commons/net/telnet/Telnet.java delete mode 100644 org/apache/commons/net/telnet/TelnetClient.java delete mode 100644 org/apache/commons/net/telnet/TelnetCommand.java delete mode 100644 org/apache/commons/net/telnet/TelnetInputStream.java delete mode 100644 org/apache/commons/net/telnet/TelnetNotificationHandler.java delete mode 100644 org/apache/commons/net/telnet/TelnetOption.java delete mode 100644 org/apache/commons/net/telnet/TelnetOptionHandler.java delete mode 100644 org/apache/commons/net/telnet/TelnetOutputStream.java delete mode 100644 org/apache/commons/net/telnet/TerminalTypeOptionHandler.java delete mode 100644 org/apache/commons/net/telnet/WindowSizeOptionHandler.java delete mode 100644 org/apache/commons/net/tftp/TFTP.java delete mode 100644 org/apache/commons/net/tftp/TFTPAckPacket.java delete mode 100644 org/apache/commons/net/tftp/TFTPClient.java delete mode 100644 org/apache/commons/net/tftp/TFTPDataPacket.java delete mode 100644 org/apache/commons/net/tftp/TFTPErrorPacket.java delete mode 100644 org/apache/commons/net/tftp/TFTPPacket.java delete mode 100644 org/apache/commons/net/tftp/TFTPPacketException.java delete mode 100644 org/apache/commons/net/tftp/TFTPReadRequestPacket.java delete mode 100644 org/apache/commons/net/tftp/TFTPRequestPacket.java delete mode 100644 org/apache/commons/net/tftp/TFTPWriteRequestPacket.java delete mode 100644 org/apache/commons/net/time/TimeTCPClient.java delete mode 100644 org/apache/commons/net/time/TimeUDPClient.java delete mode 100644 org/apache/commons/net/util/ListenerList.class delete mode 100644 org/apache/commons/net/util/ListenerList.java delete mode 100644 org/apache/commons/net/util/SubnetUtils.java delete mode 100644 org/apache/commons/net/whois/WhoisClient.java diff --git a/org/apache/commons/net/DatagramSocketClient.java b/org/apache/commons/net/DatagramSocketClient.java deleted file mode 100644 index 9199704..0000000 --- a/org/apache/commons/net/DatagramSocketClient.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/*** - * The DatagramSocketClient provides the basic operations that are required - * of client objects accessing datagram sockets. It is meant to be - * subclassed to avoid having to rewrite the same code over and over again - * to open a socket, close a socket, set timeouts, etc. Of special note - * is the {@link #setDatagramSocketFactory setDatagramSocketFactory } - * method, which allows you to control the type of DatagramSocket the - * DatagramSocketClient creates for network communications. This is - * especially useful for adding things like proxy support as well as better - * support for applets. For - * example, you could create a - * {@link org.apache.commons.net.DatagramSocketFactory} - * that - * requests browser security capabilities before creating a socket. - * All classes derived from DatagramSocketClient should use the - * {@link #_socketFactory_ _socketFactory_ } member variable to - * create DatagramSocket instances rather than instantiating - * them by directly invoking a constructor. By honoring this contract - * you guarantee that a user will always be able to provide his own - * Socket implementations by substituting his own SocketFactory. - *

- *

- * @author Daniel F. Savarese - * @see DatagramSocketFactory - ***/ - -public abstract class DatagramSocketClient -{ - /*** - * The default DatagramSocketFactory shared by all DatagramSocketClient - * instances. - ***/ - private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY = - new DefaultDatagramSocketFactory(); - - /*** The timeout to use after opening a socket. ***/ - protected int _timeout_; - - /*** The datagram socket used for the connection. ***/ - protected DatagramSocket _socket_; - - /*** - * A status variable indicating if the client's socket is currently open. - ***/ - protected boolean _isOpen_; - - /*** The datagram socket's DatagramSocketFactory. ***/ - protected DatagramSocketFactory _socketFactory_; - - /*** - * Default constructor for DatagramSocketClient. Initializes - * _socket_ to null, _timeout_ to 0, and _isOpen_ to false. - ***/ - public DatagramSocketClient() - { - _socket_ = null; - _timeout_ = 0; - _isOpen_ = false; - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - } - - - /*** - * Opens a DatagramSocket on the local host at the first available port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - *

- * @exception SocketException If the socket could not be opened or the - * timeout could not be set. - ***/ - public void open() throws SocketException - { - _socket_ = _socketFactory_.createDatagramSocket(); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - - /*** - * Opens a DatagramSocket on the local host at a specified port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - *

- * @param port The port to use for the socket. - * @exception SocketException If the socket could not be opened or the - * timeout could not be set. - ***/ - public void open(int port) throws SocketException - { - _socket_ = _socketFactory_.createDatagramSocket(port); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - - /*** - * Opens a DatagramSocket at the specified address on the local host - * at a specified port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - *

- * @param port The port to use for the socket. - * @param laddr The local address to use. - * @exception SocketException If the socket could not be opened or the - * timeout could not be set. - ***/ - public void open(int port, InetAddress laddr) throws SocketException - { - _socket_ = _socketFactory_.createDatagramSocket(port, laddr); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - - - /*** - * Closes the DatagramSocket used for the connection. - * You should call this method after you've finished using the class - * instance and also before you call {@link #open open() } - * again. _isOpen_ is set to false and _socket_ is set to null. - * If you call this method when the client socket is not open, - * a NullPointerException is thrown. - ***/ - public void close() - { - _socket_.close(); - _socket_ = null; - _isOpen_ = false; - } - - - /*** - * Returns true if the client has a currently open socket. - *

- * @return True if the client has a curerntly open socket, false otherwise. - ***/ - public boolean isOpen() - { - return _isOpen_; - } - - - /*** - * Set the default timeout in milliseconds to use when opening a socket. - * After a call to open, the timeout for the socket is set using this value. - * This method should be used prior to a call to {@link #open open()} - * and should not be confused with {@link #setSoTimeout setSoTimeout()} - * which operates on the currently open socket. _timeout_ contains - * the new timeout value. - *

- * @param timeout The timeout in milliseconds to use for the datagram socket - * connection. - ***/ - public void setDefaultTimeout(int timeout) - { - _timeout_ = timeout; - } - - - /*** - * Returns the default timeout in milliseconds that is used when - * opening a socket. - *

- * @return The default timeout in milliseconds that is used when - * opening a socket. - ***/ - public int getDefaultTimeout() - { - return _timeout_; - } - - - /*** - * Set the timeout in milliseconds of a currently open connection. - * Only call this method after a connection has been opened - * by {@link #open open()}. - *

- * @param timeout The timeout in milliseconds to use for the currently - * open datagram socket connection. - ***/ - public void setSoTimeout(int timeout) throws SocketException - { - _socket_.setSoTimeout(timeout); - } - - - /*** - * Returns the timeout in milliseconds of the currently opened socket. - * If you call this method when the client socket is not open, - * a NullPointerException is thrown. - *

- * @return The timeout in milliseconds of the currently opened socket. - ***/ - public int getSoTimeout() throws SocketException - { - return _socket_.getSoTimeout(); - } - - - /*** - * Returns the port number of the open socket on the local host used - * for the connection. If you call this method when the client socket - * is not open, a NullPointerException is thrown. - *

- * @return The port number of the open socket on the local host used - * for the connection. - ***/ - public int getLocalPort() - { - return _socket_.getLocalPort(); - } - - - /*** - * Returns the local address to which the client's socket is bound. - * If you call this method when the client socket is not open, a - * NullPointerException is thrown. - *

- * @return The local address to which the client's socket is bound. - ***/ - public InetAddress getLocalAddress() - { - return _socket_.getLocalAddress(); - } - - - /*** - * Sets the DatagramSocketFactory used by the DatagramSocketClient - * to open DatagramSockets. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - *

- * @param factory The new DatagramSocketFactory the DatagramSocketClient - * should use. - ***/ - public void setDatagramSocketFactory(DatagramSocketFactory factory) - { - if (factory == null) - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - else - _socketFactory_ = factory; - } -} diff --git a/org/apache/commons/net/DatagramSocketFactory.java b/org/apache/commons/net/DatagramSocketFactory.java deleted file mode 100644 index c152eb2..0000000 --- a/org/apache/commons/net/DatagramSocketFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/*** - * The DatagramSocketFactory interface provides a means for the - * programmer to control the creation of datagram sockets and - * provide his own DatagramSocket implementations for use by all - * classes derived from - * {@link org.apache.commons.net.DatagramSocketClient} - * . - * This allows you to provide your own DatagramSocket implementations and - * to perform security checks or browser capability requests before - * creating a DatagramSocket. - *

- *

- * @author Daniel F. Savarese - ***/ - -public interface DatagramSocketFactory -{ - - /*** - * Creates a DatagramSocket on the local host at the first available port. - *

- * @exception SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket() throws SocketException; - - /*** - * Creates a DatagramSocket on the local host at a specified port. - *

- * @param port The port to use for the socket. - * @exception SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket(int port) throws SocketException; - - /*** - * Creates a DatagramSocket at the specified address on the local host - * at a specified port. - *

- * @param port The port to use for the socket. - * @param laddr The local address to use. - * @exception SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket(int port, InetAddress laddr) - throws SocketException; -} diff --git a/org/apache/commons/net/DefaultDatagramSocketFactory.java b/org/apache/commons/net/DefaultDatagramSocketFactory.java deleted file mode 100644 index 3983fcb..0000000 --- a/org/apache/commons/net/DefaultDatagramSocketFactory.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/*** - * DefaultDatagramSocketFactory implements the DatagramSocketFactory - * interface by simply wrapping the java.net.DatagramSocket - * constructors. It is the default DatagramSocketFactory used by - * {@link org.apache.commons.net.DatagramSocketClient} - * implementations. - *

- *

- * @author Daniel F. Savarese - * @see DatagramSocketFactory - * @see DatagramSocketClient - * @see DatagramSocketClient#setDatagramSocketFactory - ***/ - -public class DefaultDatagramSocketFactory implements DatagramSocketFactory -{ - - /*** - * Creates a DatagramSocket on the local host at the first available port. - *

- * @exception SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket() throws SocketException - { - return new DatagramSocket(); - } - - /*** - * Creates a DatagramSocket on the local host at a specified port. - *

- * @param port The port to use for the socket. - * @exception SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket(int port) throws SocketException - { - return new DatagramSocket(port); - } - - /*** - * Creates a DatagramSocket at the specified address on the local host - * at a specified port. - *

- * @param port The port to use for the socket. - * @param laddr The local address to use. - * @exception SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket(int port, InetAddress laddr) - throws SocketException - { - return new DatagramSocket(port, laddr); - } -} diff --git a/org/apache/commons/net/DefaultSocketFactory.java b/org/apache/commons/net/DefaultSocketFactory.java deleted file mode 100644 index e809f84..0000000 --- a/org/apache/commons/net/DefaultSocketFactory.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; - -/*** - * DefaultSocketFactory implements the SocketFactory interface by - * simply wrapping the java.net.Socket and java.net.ServerSocket - * constructors. It is the default SocketFactory used by - * {@link org.apache.commons.net.SocketClient} - * implementations. - *

- *

- * @author Daniel F. Savarese - * @see SocketFactory - * @see SocketClient - * @see SocketClient#setSocketFactory - ***/ - -public class DefaultSocketFactory extends SocketFactory -{ - - /*** - * Creates a Socket connected to the given host and port. - *

- * @param host The hostname to connect to. - * @param port The port to connect to. - * @return A Socket connected to the given host and port. - * @exception UnknownHostException If the hostname cannot be resolved. - * @exception IOException If an I/O error occurs while creating the Socket. - ***/ - @Override - public Socket createSocket(String host, int port) - throws UnknownHostException, IOException - { - return new Socket(host, port); - } - - /*** - * Creates a Socket connected to the given host and port. - *

- * @param address The address of the host to connect to. - * @param port The port to connect to. - * @return A Socket connected to the given host and port. - * @exception IOException If an I/O error occurs while creating the Socket. - ***/ - @Override - public Socket createSocket(InetAddress address, int port) - throws IOException - { - return new Socket(address, port); - } - - /*** - * Creates a Socket connected to the given host and port and - * originating from the specified local address and port. - *

- * @param host The hostname to connect to. - * @param port The port to connect to. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @return A Socket connected to the given host and port. - * @exception UnknownHostException If the hostname cannot be resolved. - * @exception IOException If an I/O error occurs while creating the Socket. - ***/ - @Override - public Socket createSocket(String host, int port, - InetAddress localAddr, int localPort) - throws UnknownHostException, IOException - { - return new Socket(host, port, localAddr, localPort); - } - - /*** - * Creates a Socket connected to the given host and port and - * originating from the specified local address and port. - *

- * @param address The address of the host to connect to. - * @param port The port to connect to. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @return A Socket connected to the given host and port. - * @exception IOException If an I/O error occurs while creating the Socket. - ***/ - @Override - public Socket createSocket(InetAddress address, int port, - InetAddress localAddr, int localPort) - throws IOException - { - return new Socket(address, port, localAddr, localPort); - } - - /*** - * Creates a ServerSocket bound to a specified port. A port - * of 0 will create the ServerSocket on a system-determined free port. - *

- * @param port The port on which to listen, or 0 to use any free port. - * @return A ServerSocket that will listen on a specified port. - * @exception IOException If an I/O error occurs while creating - * the ServerSocket. - ***/ - public ServerSocket createServerSocket(int port) throws IOException - { - return new ServerSocket(port); - } - - /*** - * Creates a ServerSocket bound to a specified port with a given - * maximum queue length for incoming connections. A port of 0 will - * create the ServerSocket on a system-determined free port. - *

- * @param port The port on which to listen, or 0 to use any free port. - * @param backlog The maximum length of the queue for incoming connections. - * @return A ServerSocket that will listen on a specified port. - * @exception IOException If an I/O error occurs while creating - * the ServerSocket. - ***/ - public ServerSocket createServerSocket(int port, int backlog) - throws IOException - { - return new ServerSocket(port, backlog); - } - - /*** - * Creates a ServerSocket bound to a specified port on a given local - * address with a given maximum queue length for incoming connections. - * A port of 0 will - * create the ServerSocket on a system-determined free port. - *

- * @param port The port on which to listen, or 0 to use any free port. - * @param backlog The maximum length of the queue for incoming connections. - * @param bindAddr The local address to which the ServerSocket should bind. - * @return A ServerSocket that will listen on a specified port. - * @exception IOException If an I/O error occurs while creating - * the ServerSocket. - ***/ - public ServerSocket createServerSocket(int port, int backlog, - InetAddress bindAddr) - throws IOException - { - return new ServerSocket(port, backlog, bindAddr); - } -} diff --git a/org/apache/commons/net/MalformedServerReplyException.class b/org/apache/commons/net/MalformedServerReplyException.class deleted file mode 100644 index 6b04dd8..0000000 Binary files a/org/apache/commons/net/MalformedServerReplyException.class and /dev/null differ diff --git a/org/apache/commons/net/MalformedServerReplyException.java b/org/apache/commons/net/MalformedServerReplyException.java deleted file mode 100644 index 3cad5f0..0000000 --- a/org/apache/commons/net/MalformedServerReplyException.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.IOException; - -/*** - * This exception is used to indicate that the reply from a server - * could not be interpreted. Most of the NetComponents classes attempt - * to be as lenient as possible when receiving server replies. Many - * server implementations deviate from IETF protocol specifications, making - * it necessary to be as flexible as possible. However, there will be - * certain situations where it is not possible to continue an operation - * because the server reply could not be interpreted in a meaningful manner. - * In these cases, a MalformedServerReplyException should be thrown. - *

- *

- * @author Daniel F. Savarese - ***/ - -public class MalformedServerReplyException extends IOException -{ - - /*** Constructs a MalformedServerReplyException with no message ***/ - public MalformedServerReplyException() - { - super(); - } - - /*** - * Constructs a MalformedServerReplyException with a specified message. - *

- * @param message The message explaining the reason for the exception. - ***/ - public MalformedServerReplyException(String message) - { - super(message); - } - -} diff --git a/org/apache/commons/net/PrintCommandListener.java b/org/apache/commons/net/PrintCommandListener.java deleted file mode 100644 index d8e7a68..0000000 --- a/org/apache/commons/net/PrintCommandListener.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.PrintWriter; -import org.apache.commons.net.ProtocolCommandEvent; -import org.apache.commons.net.ProtocolCommandListener; - -/*** - * This is a support class for some of the example programs. It is - * a sample implementation of the ProtocolCommandListener interface - * which just prints out to a specified stream all command/reply traffic. - *

- * - * @since 2.0 - ***/ - -public class PrintCommandListener implements ProtocolCommandListener -{ - private PrintWriter __writer; - - public PrintCommandListener(PrintWriter writer) - { - __writer = writer; - } - - public void protocolCommandSent(ProtocolCommandEvent event) - { - __writer.print(event.getMessage()); - __writer.flush(); - } - - public void protocolReplyReceived(ProtocolCommandEvent event) - { - __writer.print(event.getMessage()); - __writer.flush(); - } -} - diff --git a/org/apache/commons/net/ProtocolCommandEvent.class b/org/apache/commons/net/ProtocolCommandEvent.class deleted file mode 100644 index e558b69..0000000 Binary files a/org/apache/commons/net/ProtocolCommandEvent.class and /dev/null differ diff --git a/org/apache/commons/net/ProtocolCommandEvent.java b/org/apache/commons/net/ProtocolCommandEvent.java deleted file mode 100644 index 8977c03..0000000 --- a/org/apache/commons/net/ProtocolCommandEvent.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; -import java.util.EventObject; - -/*** - * There exists a large class of IETF protocols that work by sending an - * ASCII text command and arguments to a server, and then receiving an - * ASCII text reply. For debugging and other purposes, it is extremely - * useful to log or keep track of the contents of the protocol messages. - * The ProtocolCommandEvent class coupled with the - * {@link org.apache.commons.net.ProtocolCommandListener} - * interface facilitate this process. - *

- *

- * @see ProtocolCommandListener - * @see ProtocolCommandSupport - * @author Daniel F. Savarese - ***/ - -public class ProtocolCommandEvent extends EventObject -{ - private int __replyCode; - private boolean __isCommand; - private String __message, __command; - - /*** - * Creates a ProtocolCommandEvent signalling a command was sent to - * the server. ProtocolCommandEvents created with this constructor - * should only be sent after a command has been sent, but before the - * reply has been received. - *

- * @param source The source of the event. - * @param command The string representation of the command type sent, not - * including the arguments (e.g., "STAT" or "GET"). - * @param message The entire command string verbatim as sent to the server, - * including all arguments. - ***/ - public ProtocolCommandEvent(Object source, String command, String message) - { - super(source); - __replyCode = 0; - __message = message; - __isCommand = true; - __command = command; - } - - - /*** - * Creates a ProtocolCommandEvent signalling a reply to a command was - * received. ProtocolCommandEvents created with this constructor - * should only be sent after a complete command reply has been received - * fromt a server. - *

- * @param source The source of the event. - * @param replyCode The integer code indicating the natureof the reply. - * This will be the protocol integer value for protocols - * that use integer reply codes, or the reply class constant - * corresponding to the reply for protocols like POP3 that use - * strings like OK rather than integer codes (i.e., POP3Repy.OK). - * @param message The entire reply as received from the server. - ***/ - public ProtocolCommandEvent(Object source, int replyCode, String message) - { - super(source); - __replyCode = replyCode; - __message = message; - __isCommand = false; - __command = null; - } - - /*** - * Returns the string representation of the command type sent (e.g., "STAT" - * or "GET"). If the ProtocolCommandEvent is a reply event, then null - * is returned. - *

- * @return The string representation of the command type sent, or null - * if this is a reply event. - ***/ - public String getCommand() - { - return __command; - } - - - /*** - * Returns the reply code of the received server reply. Undefined if - * this is not a reply event. - *

- * @return The reply code of the received server reply. Undefined if - * not a reply event. - ***/ - public int getReplyCode() - { - return __replyCode; - } - - /*** - * Returns true if the ProtocolCommandEvent was generated as a result - * of sending a command. - *

- * @return true If the ProtocolCommandEvent was generated as a result - * of sending a command. False otherwise. - ***/ - public boolean isCommand() - { - return __isCommand; - } - - /*** - * Returns true if the ProtocolCommandEvent was generated as a result - * of receiving a reply. - *

- * @return true If the ProtocolCommandEvent was generated as a result - * of receiving a reply. False otherwise. - ***/ - public boolean isReply() - { - return !isCommand(); - } - - /*** - * Returns the entire message sent to or received from the server. - *

- * @return The entire message sent to or received from the server. - ***/ - public String getMessage() - { - return __message; - } -} diff --git a/org/apache/commons/net/ProtocolCommandListener.class b/org/apache/commons/net/ProtocolCommandListener.class deleted file mode 100644 index 54d6a46..0000000 Binary files a/org/apache/commons/net/ProtocolCommandListener.class and /dev/null differ diff --git a/org/apache/commons/net/ProtocolCommandListener.java b/org/apache/commons/net/ProtocolCommandListener.java deleted file mode 100644 index 8089926..0000000 --- a/org/apache/commons/net/ProtocolCommandListener.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; -import java.util.EventListener; - -/*** - * There exists a large class of IETF protocols that work by sending an - * ASCII text command and arguments to a server, and then receiving an - * ASCII text reply. For debugging and other purposes, it is extremely - * useful to log or keep track of the contents of the protocol messages. - * The ProtocolCommandListener interface coupled with the - * {@link ProtocolCommandEvent} class facilitate this process. - *

- * To receive ProtocolCommandEvents, you merely implement the - * ProtocolCommandListener interface and register the class as a listener - * with a ProtocolCommandEvent source such as - * {@link org.apache.commons.net.ftp.FTPClient}. - *

- *

- * @see ProtocolCommandEvent - * @see ProtocolCommandSupport - * @author Daniel F. Savarese - ***/ - -public interface ProtocolCommandListener extends EventListener -{ - - /*** - * This method is invoked by a ProtocolCommandEvent source after - * sending a protocol command to a server. - *

- * @param event The ProtocolCommandEvent fired. - ***/ - public void protocolCommandSent(ProtocolCommandEvent event); - - /*** - * This method is invoked by a ProtocolCommandEvent source after - * receiving a reply from a server. - *

- * @param event The ProtocolCommandEvent fired. - ***/ - public void protocolReplyReceived(ProtocolCommandEvent event); - -} diff --git a/org/apache/commons/net/ProtocolCommandSupport.class b/org/apache/commons/net/ProtocolCommandSupport.class deleted file mode 100644 index 70ee4eb..0000000 Binary files a/org/apache/commons/net/ProtocolCommandSupport.class and /dev/null differ diff --git a/org/apache/commons/net/ProtocolCommandSupport.java b/org/apache/commons/net/ProtocolCommandSupport.java deleted file mode 100644 index 1a51fb6..0000000 --- a/org/apache/commons/net/ProtocolCommandSupport.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.Serializable; -import java.util.EventListener; - -import org.apache.commons.net.util.ListenerList; - -/*** - * ProtocolCommandSupport is a convenience class for managing a list of - * ProtocolCommandListeners and firing ProtocolCommandEvents. You can - * simply delegate ProtocolCommandEvent firing and listener - * registering/unregistering tasks to this class. - *

- *

- * @see ProtocolCommandEvent - * @see ProtocolCommandListener - * @author Daniel F. Savarese - ***/ - -public class ProtocolCommandSupport implements Serializable -{ - private Object __source; - private ListenerList __listeners; - - /*** - * Creates a ProtocolCommandSupport instant using the indicated source - * as the source of fired ProtocolCommandEvents. - *

- * @param source The source to use for all generated ProtocolCommandEvents. - ***/ - public ProtocolCommandSupport(Object source) - { - __listeners = new ListenerList(); - __source = source; - } - - - /*** - * Fires a ProtocolCommandEvent signalling the sending of a command to all - * registered listeners, invoking their - * {@link org.apache.commons.net.ProtocolCommandListener#protocolCommandSent protocolCommandSent() } - * methods. - *

- * @param command The string representation of the command type sent, not - * including the arguments (e.g., "STAT" or "GET"). - * @param message The entire command string verbatim as sent to the server, - * including all arguments. - ***/ - public void fireCommandSent(String command, String message) - { - ProtocolCommandEvent event; - - event = new ProtocolCommandEvent(__source, command, message); - - for (EventListener listener : __listeners) - { - ((ProtocolCommandListener)listener).protocolCommandSent(event); - } - } - - /*** - * Fires a ProtocolCommandEvent signalling the reception of a command reply - * to all registered listeners, invoking their - * {@link org.apache.commons.net.ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() } - * methods. - *

- * @param replyCode The integer code indicating the natureof the reply. - * This will be the protocol integer value for protocols - * that use integer reply codes, or the reply class constant - * corresponding to the reply for protocols like POP3 that use - * strings like OK rather than integer codes (i.e., POP3Repy.OK). - * @param message The entire reply as received from the server. - ***/ - public void fireReplyReceived(int replyCode, String message) - { - ProtocolCommandEvent event; - event = new ProtocolCommandEvent(__source, replyCode, message); - - for (EventListener listener : __listeners) - { - ((ProtocolCommandListener)listener).protocolReplyReceived(event); - } - } - - /*** - * Adds a ProtocolCommandListener. - *

- * @param listener The ProtocolCommandListener to add. - ***/ - public void addProtocolCommandListener(ProtocolCommandListener listener) - { - __listeners.addListener(listener); - } - - /*** - * Removes a ProtocolCommandListener. - *

- * @param listener The ProtocolCommandListener to remove. - ***/ - public void removeProtocolCommandListener(ProtocolCommandListener listener) - { - __listeners.removeListener(listener); - } - - - /*** - * Returns the number of ProtocolCommandListeners currently registered. - *

- * @return The number of ProtocolCommandListeners currently registered. - ***/ - public int getListenerCount() - { - return __listeners.getListenerCount(); - } - -} - diff --git a/org/apache/commons/net/SocketClient.class b/org/apache/commons/net/SocketClient.class deleted file mode 100644 index 216f590..0000000 Binary files a/org/apache/commons/net/SocketClient.class and /dev/null differ diff --git a/org/apache/commons/net/SocketClient.java b/org/apache/commons/net/SocketClient.java deleted file mode 100644 index a5a8ead..0000000 --- a/org/apache/commons/net/SocketClient.java +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketException; -import java.net.UnknownHostException; - -import javax.net.ServerSocketFactory; -import javax.net.SocketFactory; - - -/** - * The SocketClient provides the basic operations that are required of - * client objects accessing sockets. It is meant to be - * subclassed to avoid having to rewrite the same code over and over again - * to open a socket, close a socket, set timeouts, etc. Of special note - * is the {@link #setSocketFactory setSocketFactory } - * method, which allows you to control the type of Socket the SocketClient - * creates for initiating network connections. This is especially useful - * for adding SSL or proxy support as well as better support for applets. For - * example, you could create a - * {@link org.apache.commons.net.SocketFactory} that - * requests browser security capabilities before creating a socket. - * All classes derived from SocketClient should use the - * {@link #_socketFactory_ _socketFactory_ } member variable to - * create Socket and ServerSocket instances rather than instanting - * them by directly invoking a constructor. By honoring this contract - * you guarantee that a user will always be able to provide his own - * Socket implementations by substituting his own SocketFactory. - * @author Daniel F. Savarese - * @see SocketFactory - */ -public abstract class SocketClient -{ - /** - * The end of line character sequence used by most IETF protocols. That - * is a carriage return followed by a newline: "\r\n" - */ - public static final String NETASCII_EOL = "\r\n"; - - /** The default SocketFactory shared by all SocketClient instances. */ - private static final SocketFactory __DEFAULT_SOCKET_FACTORY = - SocketFactory.getDefault(); - - private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = - ServerSocketFactory.getDefault(); - - /** The timeout to use after opening a socket. */ - protected int _timeout_; - - /** The socket used for the connection. */ - protected Socket _socket_; - - /** The default port the client should connect to. */ - protected int _defaultPort_; - - /** The socket's InputStream. */ - protected InputStream _input_; - - /** The socket's OutputStream. */ - protected OutputStream _output_; - - /** The socket's SocketFactory. */ - protected SocketFactory _socketFactory_; - - /** The socket's ServerSocket Factory. */ - protected ServerSocketFactory _serverSocketFactory_; - - /** The socket's connect timeout (0 = infinite timeout) */ - private static final int DEFAULT_CONNECT_TIMEOUT = 0; - protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; - - /** - * Default constructor for SocketClient. Initializes - * _socket_ to null, _timeout_ to 0, _defaultPort to 0, - * _isConnected_ to false, and _socketFactory_ to a shared instance of - * {@link org.apache.commons.net.DefaultSocketFactory}. - */ - public SocketClient() - { - _socket_ = null; - _input_ = null; - _output_ = null; - _timeout_ = 0; - _defaultPort_ = 0; - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; - } - - - /** - * Because there are so many connect() methods, the _connectAction_() - * method is provided as a means of performing some action immediately - * after establishing a connection, rather than reimplementing all - * of the connect() methods. The last action performed by every - * connect() method after opening a socket is to call this method. - *

- * This method sets the timeout on the just opened socket to the default - * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, - * sets _input_ and _output_ to the socket's InputStream and OutputStream - * respectively, and sets _isConnected_ to true. - *

- * Subclasses overriding this method should start by calling - * super._connectAction_() first to ensure the - * initialization of the aforementioned protected variables. - */ - protected void _connectAction_() throws IOException - { - _socket_.setSoTimeout(_timeout_); - _input_ = _socket_.getInputStream(); - _output_ = _socket_.getOutputStream(); - } - - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(InetAddress host, int port) - throws SocketException, IOException - { - _socket_ = _socketFactory_.createSocket(); - _socket_.connect(new InetSocketAddress(host, port), connectTimeout); - - _connectAction_(); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @exception UnknownHostException If the hostname cannot be resolved. - */ - public void connect(String hostname, int port) - throws SocketException, IOException - { - _socket_= _socketFactory_.createSocket(); - _socket_.connect(new InetSocketAddress(hostname, port), connectTimeout); - - _connectAction_(); - } - - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(InetAddress host, int port, - InetAddress localAddr, int localPort) - throws SocketException, IOException - { - _socket_ = _socketFactory_.createSocket(); - _socket_.bind(new InetSocketAddress(localAddr, localPort)); - _socket_.connect(new InetSocketAddress(host, port), connectTimeout); - - _connectAction_(); - } - - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @exception UnknownHostException If the hostname cannot be resolved. - */ - public void connect(String hostname, int port, - InetAddress localAddr, int localPort) - throws SocketException, IOException - { - _socket_ = - _socketFactory_.createSocket(hostname, port, localAddr, localPort); - _connectAction_(); - } - - - /** - * Opens a Socket connected to a remote host at the current default port - * and originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(InetAddress host) throws SocketException, IOException - { - connect(host, _defaultPort_); - } - - - /** - * Opens a Socket connected to a remote host at the current default - * port and originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @exception UnknownHostException If the hostname cannot be resolved. - */ - public void connect(String hostname) throws SocketException, IOException - { - connect(hostname, _defaultPort_); - } - - - /** - * Disconnects the socket connection. - * You should call this method after you've finished using the class - * instance and also before you call - * {@link #connect connect() } - * again. _isConnected_ is set to false, _socket_ is set to null, - * _input_ is set to null, and _output_ is set to null. - *

- * @exception IOException If there is an error closing the socket. - */ - public void disconnect() throws IOException - { - if (_socket_ != null) _socket_.close(); - if (_input_ != null) _input_.close(); - if (_output_ != null) _output_.close(); - if (_socket_ != null) _socket_ = null; - _input_ = null; - _output_ = null; - } - - - /** - * Returns true if the client is currently connected to a server. - *

- * @return True if the client is currently connected to a server, - * false otherwise. - */ - public boolean isConnected() - { - if (_socket_ == null) - return false; - - return _socket_.isConnected(); - } - - - /** - * Sets the default port the SocketClient should connect to when a port - * is not specified. The {@link #_defaultPort_ _defaultPort_ } - * variable stores this value. If never set, the default port is equal - * to zero. - *

- * @param port The default port to set. - */ - public void setDefaultPort(int port) - { - _defaultPort_ = port; - } - - /** - * Returns the current value of the default port (stored in - * {@link #_defaultPort_ _defaultPort_ }). - *

- * @return The current value of the default port. - */ - public int getDefaultPort() - { - return _defaultPort_; - } - - - /** - * Set the default timeout in milliseconds to use when opening a socket. - * This value is only used previous to a call to - * {@link #connect connect()} - * and should not be confused with {@link #setSoTimeout setSoTimeout()} - * which operates on an the currently opened socket. _timeout_ contains - * the new timeout value. - *

- * @param timeout The timeout in milliseconds to use for the socket - * connection. - */ - public void setDefaultTimeout(int timeout) - { - _timeout_ = timeout; - } - - - /** - * Returns the default timeout in milliseconds that is used when - * opening a socket. - *

- * @return The default timeout in milliseconds that is used when - * opening a socket. - */ - public int getDefaultTimeout() - { - return _timeout_; - } - - - /** - * Set the timeout in milliseconds of a currently open connection. - * Only call this method after a connection has been opened - * by {@link #connect connect()}. - *

- * @param timeout The timeout in milliseconds to use for the currently - * open socket connection. - * @exception SocketException If the operation fails. - */ - public void setSoTimeout(int timeout) throws SocketException - { - _socket_.setSoTimeout(timeout); - } - - - /** - * Set the underlying socket send buffer size. - *

- * @param size The size of the buffer in bytes. - * @throws SocketException - * @since 2.0 - */ - public void setSendBufferSize(int size) throws SocketException { - _socket_.setSendBufferSize(size); - } - - - /** - * Sets the underlying socket receive buffer size. - *

- * @param size The size of the buffer in bytes. - * @throws SocketException - * @since 2.0 - */ - public void setReceiveBufferSize(int size) throws SocketException { - _socket_.setReceiveBufferSize(size); - } - - - /** - * Returns the timeout in milliseconds of the currently opened socket. - *

- * @return The timeout in milliseconds of the currently opened socket. - * @exception SocketException If the operation fails. - */ - public int getSoTimeout() throws SocketException - { - return _socket_.getSoTimeout(); - } - - /** - * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the - * currently opened socket. - *

- * @param on True if Nagle's algorithm is to be enabled, false if not. - * @exception SocketException If the operation fails. - */ - public void setTcpNoDelay(boolean on) throws SocketException - { - _socket_.setTcpNoDelay(on); - } - - - /** - * Returns true if Nagle's algorithm is enabled on the currently opened - * socket. - *

- * @return True if Nagle's algorithm is enabled on the currently opened - * socket, false otherwise. - * @exception SocketException If the operation fails. - */ - public boolean getTcpNoDelay() throws SocketException - { - return _socket_.getTcpNoDelay(); - } - - - /** - * Sets the SO_LINGER timeout on the currently opened socket. - *

- * @param on True if linger is to be enabled, false if not. - * @param val The linger timeout (in hundredths of a second?) - * @exception SocketException If the operation fails. - */ - public void setSoLinger(boolean on, int val) throws SocketException - { - _socket_.setSoLinger(on, val); - } - - - /** - * Returns the current SO_LINGER timeout of the currently opened socket. - *

- * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns - * -1. - * @exception SocketException If the operation fails. - */ - public int getSoLinger() throws SocketException - { - return _socket_.getSoLinger(); - } - - - /** - * Returns the port number of the open socket on the local host used - * for the connection. - *

- * @return The port number of the open socket on the local host used - * for the connection. - */ - public int getLocalPort() - { - return _socket_.getLocalPort(); - } - - - /** - * Returns the local address to which the client's socket is bound. - *

- * @return The local address to which the client's socket is bound. - */ - public InetAddress getLocalAddress() - { - return _socket_.getLocalAddress(); - } - - /** - * Returns the port number of the remote host to which the client is - * connected. - *

- * @return The port number of the remote host to which the client is - * connected. - */ - public int getRemotePort() - { - return _socket_.getPort(); - } - - - /** - * @return The remote address to which the client is connected. - */ - public InetAddress getRemoteAddress() - { - return _socket_.getInetAddress(); - } - - - /** - * Verifies that the remote end of the given socket is connected to the - * the same host that the SocketClient is currently connected to. This - * is useful for doing a quick security check when a client needs to - * accept a connection from a server, such as an FTP data connection or - * a BSD R command standard error stream. - *

- * @return True if the remote hosts are the same, false if not. - */ - public boolean verifyRemote(Socket socket) - { - InetAddress host1, host2; - - host1 = socket.getInetAddress(); - host2 = getRemoteAddress(); - - return host1.equals(host2); - } - - - /** - * Sets the SocketFactory used by the SocketClient to open socket - * connections. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - *

- * @param factory The new SocketFactory the SocketClient should use. - */ - public void setSocketFactory(SocketFactory factory) - { - if (factory == null) - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - else - _socketFactory_ = factory; - } - - /** - * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket - * connections. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - *

- * @param factory The new ServerSocketFactory the SocketClient should use. - * @since 2.0 - */ - public void setServerSocketFactory(ServerSocketFactory factory) { - if (factory == null) - _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; - else - _serverSocketFactory_ = factory; - } - - /** - * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's - * connect() method. - * @param connectTimeout The connection timeout to use (in ms) - * @since 2.0 - */ - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - /** - * Get the underlying socket connection timeout. - * @return - * @since 2.0 - */ - public int getConnectTimeout() { - return connectTimeout; - } - - - -} - - diff --git a/org/apache/commons/net/bsd/RCommandClient.java b/org/apache/commons/net/bsd/RCommandClient.java deleted file mode 100644 index 50cb87a..0000000 --- a/org/apache/commons/net/bsd/RCommandClient.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.bsd; - -import java.io.IOException; -import java.io.InputStream; -import java.net.BindException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; - -import org.apache.commons.net.io.SocketInputStream; - -/*** - * RCommandClient is very similar to - * {@link org.apache.commons.net.bsd.RExecClient}, - * from which it is derived, and implements the rcmd() facility that - * first appeared in 4.2BSD Unix. rcmd() is the facility used by the rsh - * (rshell) and other commands to execute a command on another machine - * from a trusted host without issuing a password. The trust relationship - * between two machines is established by the contents of a machine's - * /etc/hosts.equiv file and a user's .rhosts file. These files specify - * from which hosts and accounts on those hosts rcmd() requests will be - * accepted. The only additional measure for establishing trust is that - * all client connections must originate from a port between 512 and 1023. - * Consequently, there is an upper limit to the number of rcmd connections - * that can be running simultaneously. The required ports are reserved - * ports on Unix systems, and can only be bound by a - * process running with root permissions (to accomplish this rsh, rlogin, - * and related commands usualy have the suid bit set). Therefore, on a - * Unix system, you will only be able to successfully use the RCommandClient - * class if the process runs as root. However, there is no such restriction - * on Windows95 and some other systems. The security risks are obvious. - * However, when carefully used, rcmd() can be very useful when used behind - * a firewall. - *

- * As with virtually all of the client classes in org.apache.commons.net, this - * class derives from SocketClient. But it overrides most of its connection - * methods so that the local Socket will originate from an acceptable - * rshell port. The way to use RCommandClient is to first connect - * to the server, call the {@link #rcommand rcommand() } method, - * and then - * fetch the connection's input, output, and optionally error streams. - * Interaction with the remote command is controlled entirely through the - * I/O streams. Once you have finished processing the streams, you should - * invoke {@link org.apache.commons.net.bsd.RExecClient#disconnect disconnect() } - * to clean up properly. - *

- * By default the standard output and standard error streams of the - * remote process are transmitted over the same connection, readable - * from the input stream returned by - * {@link org.apache.commons.net.bsd.RExecClient#getInputStream getInputStream() } - * . However, it is - * possible to tell the rshd daemon to return the standard error - * stream over a separate connection, readable from the input stream - * returned by {@link org.apache.commons.net.bsd.RExecClient#getErrorStream getErrorStream() } - * . You - * can specify that a separate connection should be created for standard - * error by setting the boolean separateErrorStream - * parameter of {@link #rcommand rcommand() } to true . - * The standard input of the remote process can be written to through - * the output stream returned by - * {@link org.apache.commons.net.bsd.RExecClient#getOutputStream getOutputStream() } - * . - *

- *

- * @author Daniel F. Savarese - * @see org.apache.commons.net.SocketClient - * @see RExecClient - * @see RLoginClient - ***/ - -public class RCommandClient extends RExecClient -{ - /*** - * The default rshell port. Set to 514 in BSD Unix. - ***/ - public static final int DEFAULT_PORT = 514; - - /*** - * The smallest port number an rcmd client may use. By BSD convention - * this number is 512. - ***/ - public static final int MIN_CLIENT_PORT = 512; - - /*** - * The largest port number an rcmd client may use. By BSD convention - * this number is 1023. - ***/ - public static final int MAX_CLIENT_PORT = 1023; - - // Overrides method in RExecClient in order to implement proper - // port number limitations. - @Override - InputStream _createErrorStream() throws IOException - { - int localPort; - ServerSocket server; - Socket socket; - - localPort = MAX_CLIENT_PORT; - server = null; // Keep compiler from barfing - - for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort) - { - try - { - server = _serverSocketFactory_.createServerSocket(localPort, 1, - getLocalAddress()); - } - catch (SocketException e) - { - continue; - } - break; - } - - if (localPort < MIN_CLIENT_PORT) - throw new BindException("All ports in use."); - - _output_.write(Integer.toString(server.getLocalPort()).getBytes()); - _output_.write('\0'); - _output_.flush(); - - socket = server.accept(); - server.close(); - - if (isRemoteVerificationEnabled() && !verifyRemote(socket)) - { - socket.close(); - throw new IOException( - "Security violation: unexpected connection attempt by " + - socket.getInetAddress().getHostAddress()); - } - - return (new SocketInputStream(socket, socket.getInputStream())); - } - - /*** - * The default RCommandClient constructor. Initializes the - * default port to DEFAULT_PORT . - ***/ - public RCommandClient() - { - setDefaultPort(DEFAULT_PORT); - } - - - /*** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address using a port in a range - * acceptable to the BSD rshell daemon. - * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @exception SocketException If the socket timeout could not be set. - * @exception BindException If all acceptable rshell ports are in use. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - ***/ - public void connect(InetAddress host, int port, InetAddress localAddr) - throws SocketException, BindException, IOException - { - int localPort; - - localPort = MAX_CLIENT_PORT; - - for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort) - { - try - { - _socket_ = - _socketFactory_.createSocket(host, port, localAddr, localPort); - } - catch (BindException be) { - continue; - } - catch (SocketException e) - { - continue; - } - break; - } - - if (localPort < MIN_CLIENT_PORT) - throw new BindException("All ports in use or insufficient permssion."); - - _connectAction_(); - } - - - - /*** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a port in a range acceptable - * to the BSD rshell daemon. - * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @exception SocketException If the socket timeout could not be set. - * @exception BindException If all acceptable rshell ports are in use. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - ***/ - @Override - public void connect(InetAddress host, int port) - throws SocketException, IOException - { - connect(host, port, InetAddress.getLocalHost()); - } - - - /*** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a port in a range acceptable - * to the BSD rshell daemon. - * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @exception SocketException If the socket timeout could not be set. - * @exception BindException If all acceptable rshell ports are in use. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @exception UnknownHostException If the hostname cannot be resolved. - ***/ - @Override - public void connect(String hostname, int port) - throws SocketException, IOException - { - connect(InetAddress.getByName(hostname), port, InetAddress.getLocalHost()); - } - - - /*** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address using a port in a range - * acceptable to the BSD rshell daemon. - * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @exception SocketException If the socket timeout could not be set. - * @exception BindException If all acceptable rshell ports are in use. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - ***/ - public void connect(String hostname, int port, InetAddress localAddr) - throws SocketException, IOException - { - connect(InetAddress.getByName(hostname), port, localAddr); - } - - - /*** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. The - * local port must lie between MIN_CLIENT_PORT and - * MAX_CLIENT_PORT or an IllegalArgumentException will - * be thrown. - * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @exception IllegalArgumentException If an invalid local port number - * is specified. - ***/ - @Override - public void connect(InetAddress host, int port, - InetAddress localAddr, int localPort) - throws SocketException, IOException, IllegalArgumentException - { - if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT) - throw new IllegalArgumentException("Invalid port number " + localPort); - super.connect(host, port, localAddr, localPort); - } - - - /*** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. The - * local port must lie between MIN_CLIENT_PORT and - * MAX_CLIENT_PORT or an IllegalArgumentException will - * be thrown. - * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @exception SocketException If the socket timeout could not be set. - * @exception IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @exception UnknownHostException If the hostname cannot be resolved. - * @exception IllegalArgumentException If an invalid local port number - * is specified. - ***/ - @Override - public void connect(String hostname, int port, - InetAddress localAddr, int localPort) - throws SocketException, IOException, IllegalArgumentException - { - if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT) - throw new IllegalArgumentException("Invalid port number " + localPort); - super.connect(hostname, port, localAddr, localPort); - } - - - /*** - * Remotely executes a command through the rshd daemon on the server - * to which the RCommandClient is connected. After calling this method, - * you may interact with the remote process through its standard input, - * output, and error streams. You will typically be able to detect - * the termination of the remote process after reaching end of file - * on its standard output (accessible through - * {@link #getInputStream getInputStream() }. Disconnecting - * from the server or closing the process streams before reaching - * end of file will not necessarily terminate the remote process. - *

- * If a separate error stream is requested, the remote server will - * connect to a local socket opened by RCommandClient, providing an - * independent stream through which standard error will be transmitted. - * The local socket must originate from a secure port (512 - 1023), - * and rcommand() ensures that this will be so. - * RCommandClient will also do a simple security check when it accepts a - * connection for this error stream. If the connection does not originate - * from the remote server, an IOException will be thrown. This serves as - * a simple protection against possible hijacking of the error stream by - * an attacker monitoring the rexec() negotiation. You may disable this - * behavior with - * {@link org.apache.commons.net.bsd.RExecClient#setRemoteVerificationEnabled setRemoteVerificationEnabled()} - * . - *

- * @param localUsername The user account on the local machine that is - * requesting the command execution. - * @param remoteUsername The account name on the server through which to - * execute the command. - * @param command The command, including any arguments, to execute. - * @param separateErrorStream True if you would like the standard error - * to be transmitted through a different stream than standard output. - * False if not. - * @exception IOException If the rcommand() attempt fails. The exception - * will contain a message indicating the nature of the failure. - ***/ - public void rcommand(String localUsername, String remoteUsername, - String command, boolean separateErrorStream) - throws IOException - { - rexec(localUsername, remoteUsername, command, separateErrorStream); - } - - - /*** - * Same as - * rcommand(localUsername, remoteUsername, command, false); - ***/ - public void rcommand(String localUsername, String remoteUsername, - String command) - throws IOException - { - rcommand(localUsername, remoteUsername, command, false); - } - -} - diff --git a/org/apache/commons/net/bsd/RExecClient.java b/org/apache/commons/net/bsd/RExecClient.java deleted file mode 100644 index 2924120..0000000 --- a/org/apache/commons/net/bsd/RExecClient.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.bsd; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.ServerSocket; -import java.net.Socket; - -import org.apache.commons.net.SocketClient; -import org.apache.commons.net.io.SocketInputStream; - -/*** - * RExecClient implements the rexec() facility that first appeared in - * 4.2BSD Unix. This class will probably only be of use for connecting - * to Unix systems and only when the rexecd daemon is configured to run, - * which is a rarity these days because of the security risks involved. - * However, rexec() can be very useful for performing administrative tasks - * on a network behind a firewall. - *

- * As with virtually all of the client classes in org.apache.commons.net, this - * class derives from SocketClient, inheriting its connection methods. - * The way to use RExecClient is to first connect - * to the server, call the {@link #rexec rexec() } method, and then - * fetch the connection's input, output, and optionally error streams. - * Interaction with the remote command is controlled entirely through the - * I/O streams. Once you have finished processing the streams, you should - * invoke {@link #disconnect disconnect() } to clean up properly. - *

- * By default the standard output and standard error streams of the - * remote process are transmitted over the same connection, readable - * from the input stream returned by - * {@link #getInputStream getInputStream() }. However, it is - * possible to tell the rexecd daemon to return the standard error - * stream over a separate connection, readable from the input stream - * returned by {@link #getErrorStream getErrorStream() }. You - * can specify that a separate connection should be created for standard - * error by setting the boolean separateErrorStream - * parameter of {@link #rexec rexec() } to true . - * The standard input of the remote process can be written to through - * the output stream returned by - * {@link #getOutputStream getOutputSream() }. - *

- *

- * @author Daniel F. Savarese - * @see SocketClient - * @see RCommandClient - * @see RLoginClient - ***/ - -public class RExecClient extends SocketClient -{ - /*** - * The default rexec port. Set to 512 in BSD Unix. - ***/ - public static final int DEFAULT_PORT = 512; - - private boolean __remoteVerificationEnabled; - - /*** - * If a separate error stream is requested, _errorStream_ - * will point to an InputStream from which the standard error of the - * remote process can be read (after a call to rexec()). Otherwise, - * _errorStream_ will be null. - ***/ - protected InputStream _errorStream_; - - // This can be overridden in local package to implement port range - // limitations of rcmd and rlogin - InputStream _createErrorStream() throws IOException - { - ServerSocket server; - Socket socket; - - server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); - - _output_.write(Integer.toString(server.getLocalPort()).getBytes()); - _output_.write('\0'); - _output_.flush(); - - socket = server.accept(); - server.close(); - - if (__remoteVerificationEnabled && !verifyRemote(socket)) - { - socket.close(); - throw new IOException( - "Security violation: unexpected connection attempt by " + - socket.getInetAddress().getHostAddress()); - } - - return (new SocketInputStream(socket, socket.getInputStream())); - } - - - /*** - * The default RExecClient constructor. Initializes the - * default port to DEFAULT_PORT . - ***/ - public RExecClient() - { - _errorStream_ = null; - setDefaultPort(DEFAULT_PORT); - } - - - /*** - * Returns the InputStream from which the standard outputof the remote - * process can be read. The input stream will only be set after a - * successful rexec() invocation. - *

- * @return The InputStream from which the standard output of the remote - * process can be read. - ***/ - public InputStream getInputStream() - { - return _input_; - } - - - /*** - * Returns the OutputStream through which the standard input of the remote - * process can be written. The output stream will only be set after a - * successful rexec() invocation. - *

- * @return The OutputStream through which the standard input of the remote - * process can be written. - ***/ - public OutputStream getOutputStream() - { - return _output_; - } - - - /*** - * Returns the InputStream from which the standard error of the remote - * process can be read if a separate error stream is requested from - * the server. Otherwise, null will be returned. The error stream - * will only be set after a successful rexec() invocation. - *

- * @return The InputStream from which the standard error of the remote - * process can be read if a separate error stream is requested from - * the server. Otherwise, null will be returned. - ***/ - public InputStream getErrorStream() - { - return _errorStream_; - } - - - /*** - * Remotely executes a command through the rexecd daemon on the server - * to which the RExecClient is connected. After calling this method, - * you may interact with the remote process through its standard input, - * output, and error streams. You will typically be able to detect - * the termination of the remote process after reaching end of file - * on its standard output (accessible through - * {@link #getInputStream getInputStream() }. Disconnecting - * from the server or closing the process streams before reaching - * end of file will not necessarily terminate the remote process. - *

- * If a separate error stream is requested, the remote server will - * connect to a local socket opened by RExecClient, providing an - * independent stream through which standard error will be transmitted. - * RExecClient will do a simple security check when it accepts a - * connection for this error stream. If the connection does not originate - * from the remote server, an IOException will be thrown. This serves as - * a simple protection against possible hijacking of the error stream by - * an attacker monitoring the rexec() negotiation. You may disable this - * behavior with {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()} - * . - *

- * @param username The account name on the server through which to execute - * the command. - * @param password The plain text password of the user account. - * @param command The command, including any arguments, to execute. - * @param separateErrorStream True if you would like the standard error - * to be transmitted through a different stream than standard output. - * False if not. - * @exception IOException If the rexec() attempt fails. The exception - * will contain a message indicating the nature of the failure. - ***/ - public void rexec(String username, String password, - String command, boolean separateErrorStream) - throws IOException - { - int ch; - - if (separateErrorStream) - { - _errorStream_ = _createErrorStream(); - } - else - { - _output_.write('\0'); - } - - _output_.write(username.getBytes()); - _output_.write('\0'); - _output_.write(password.getBytes()); - _output_.write('\0'); - _output_.write(command.getBytes()); - _output_.write('\0'); - _output_.flush(); - - ch = _input_.read(); - if (ch > 0) - { - StringBuffer buffer = new StringBuffer(); - - while ((ch = _input_.read()) != -1 && ch != '\n') - buffer.append((char)ch); - - throw new IOException(buffer.toString()); - } - else if (ch < 0) - { - throw new IOException("Server closed connection."); - } - } - - - /*** - * Same as rexec(username, password, command, false); - ***/ - public void rexec(String username, String password, - String command) - throws IOException - { - rexec(username, password, command, false); - } - - /*** - * Disconnects from the server, closing all associated open sockets and - * streams. - *

- * @exception IOException If there an error occurs while disconnecting. - ***/ - @Override - public void disconnect() throws IOException - { - if (_errorStream_ != null) - _errorStream_.close(); - _errorStream_ = null; - super.disconnect(); - } - - - /*** - * Enable or disable verification that the remote host connecting to - * create a separate error stream is the same as the host to which - * the standard out stream is connected. The default is for verification - * to be enabled. You may set this value at any time, whether the - * client is currently connected or not. - *

- * @param enable True to enable verification, false to disable verification. - ***/ - public final void setRemoteVerificationEnabled(boolean enable) - { - __remoteVerificationEnabled = enable; - } - - /*** - * Return whether or not verification of the remote host providing a - * separate error stream is enabled. The default behavior is for - * verification to be enabled. - *

- * @return True if verification is enabled, false if not. - ***/ - public final boolean isRemoteVerificationEnabled() - { - return __remoteVerificationEnabled; - } - -} - diff --git a/org/apache/commons/net/bsd/RLoginClient.java b/org/apache/commons/net/bsd/RLoginClient.java deleted file mode 100644 index 3d7c63c..0000000 --- a/org/apache/commons/net/bsd/RLoginClient.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.bsd; - -import java.io.IOException; - -/*** - * RLoginClient is very similar to - * {@link org.apache.commons.net.bsd.RCommandClient}, - * from which it is derived, and uses the rcmd() facility implemented - * in RCommandClient to implement the functionality of the rlogin command that - * first appeared in 4.2BSD Unix. rlogin is a command used to login to - * a remote machine from a trusted host, sometimes without issuing a - * password. The trust relationship is the same as described in - * the documentation for - * {@link org.apache.commons.net.bsd.RCommandClient}. - *

- * As with virtually all of the client classes in org.apache.commons.net, this - * class derives from SocketClient. But it relies on the connection - * methods defined in RcommandClient which ensure that the local Socket - * will originate from an acceptable rshell port. The way to use - * RLoginClient is to first connect - * to the server, call the {@link #rlogin rlogin() } method, - * and then - * fetch the connection's input and output streams. - * Interaction with the remote command is controlled entirely through the - * I/O streams. Once you have finished processing the streams, you should - * invoke {@link org.apache.commons.net.bsd.RExecClient#disconnect disconnect() } - * to clean up properly. - *

- * The standard output and standard error streams of the - * remote process are transmitted over the same connection, readable - * from the input stream returned by - * {@link org.apache.commons.net.bsd.RExecClient#getInputStream getInputStream() } - * . Unlike RExecClient and RCommandClient, it is - * not possible to tell the rlogind daemon to return the standard error - * stream over a separate connection. - * {@link org.apache.commons.net.bsd.RExecClient#getErrorStream getErrorStream() } - * will always return null. - * The standard input of the remote process can be written to through - * the output stream returned by - * {@link org.apache.commons.net.bsd.RExecClient#getOutputStream getOutputSream() } - * . - *

- *

- * @author Daniel F. Savarese - * @see org.apache.commons.net.SocketClient - * @see RExecClient - * @see RCommandClient - ***/ - -public class RLoginClient extends RCommandClient -{ - /*** - * The default rlogin port. Set to 513 in BSD Unix and according - * to RFC 1282. - ***/ - public static final int DEFAULT_PORT = 513; - - /*** - * The default RLoginClient constructor. Initializes the - * default port to DEFAULT_PORT . - ***/ - public RLoginClient() - { - setDefaultPort(DEFAULT_PORT); - } - - - /*** - * Logins into a remote machine through the rlogind daemon on the server - * to which the RLoginClient is connected. After calling this method, - * you may interact with the remote login shell through its standard input - * and output streams. Standard error is sent over the same stream as - * standard output. You will typically be able to detect - * the termination of the remote login shell after reaching end of file - * on its standard output (accessible through - * {@link #getInputStream getInputStream() }. Disconnecting - * from the server or closing the process streams before reaching - * end of file will terminate the remote login shell in most cases. - *

- * If user authentication fails, the rlogind daemon will request that - * a password be entered interactively. You will be able to read the - * prompt from the output stream of the RLoginClient and write the - * password to the input stream of the RLoginClient. - *

- * @param localUsername The user account on the local machine that is - * trying to login to the remote host. - * @param remoteUsername The account name on the server that is - * being logged in to. - * @param terminalType The name of the user's terminal (e.g., "vt100", - * "network", etc.) - * @param terminalSpeed The speed of the user's terminal, expressed - * as a baud rate or bps (e.g., 9600 or 38400) - * @exception IOException If the rlogin() attempt fails. The exception - * will contain a message indicating the nature of the failure. - ***/ - public void rlogin(String localUsername, String remoteUsername, - String terminalType, int terminalSpeed) - throws IOException - { - rexec(localUsername, remoteUsername, terminalType + "/" + terminalSpeed, - false); - } - - /*** - * Same as the other rlogin method, but no terminal speed is defined. - ***/ - public void rlogin(String localUsername, String remoteUsername, - String terminalType) - throws IOException - { - rexec(localUsername, remoteUsername, terminalType, false); - } - -} diff --git a/org/apache/commons/net/chargen/CharGenTCPClient.java b/org/apache/commons/net/chargen/CharGenTCPClient.java deleted file mode 100644 index a023e58..0000000 --- a/org/apache/commons/net/chargen/CharGenTCPClient.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.chargen; - -import java.io.InputStream; - -import org.apache.commons.net.SocketClient; - -/*** - * The CharGenTCPClient class is a TCP implementation of a client for the - * character generator protocol described in RFC 864. It can also be - * used for Systat (RFC 866), Quote of the Day (RFC 865), and netstat - * (port 15). All of these protocols involve connecting to the appropriate - * port, and reading data from an input stream. The chargen protocol - * actually sends data until the receiving end closes the connection. All - * of the others send only a fixed amount of data and then close the - * connection. - *

- * To use the CharGenTCPClient class, just establish a - * connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * and call {@link #getInputStream getInputStream() } to access - * the data. Don't close the input stream when you're done with it. Rather, - * call {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to clean up properly. - *

- *

- * @author Daniel F. Savarese - * @see CharGenUDPClient - ***/ - -public final class CharGenTCPClient extends SocketClient -{ - /*** The systat port value of 11 according to RFC 866. ***/ - public static final int SYSTAT_PORT = 11; - /*** The netstat port value of 19. ***/ - public static final int NETSTAT_PORT = 15; - /*** The quote of the day port value of 17 according to RFC 865. ***/ - public static final int QUOTE_OF_DAY_PORT = 17; - /*** The character generator port value of 19 according to RFC 864. ***/ - public static final int CHARGEN_PORT = 19; - /*** The default chargen port. It is set to 19 according to RFC 864. ***/ - public static final int DEFAULT_PORT = 19; - - /*** - * The default constructor for CharGenTCPClient. It merely sets the - * default port to DEFAULT_PORT . - ***/ - public CharGenTCPClient () - { - setDefaultPort(DEFAULT_PORT); - } - - /*** - * Returns an InputStream from which the server generated data can be - * read. You should NOT close the InputStream when you're finished - * reading from it. Rather, you should call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to clean up properly. - *

- * @return An InputStream from which the server generated data can be read. - ***/ - public InputStream getInputStream() - { - return _input_; - } -} - - - - diff --git a/org/apache/commons/net/chargen/CharGenUDPClient.java b/org/apache/commons/net/chargen/CharGenUDPClient.java deleted file mode 100644 index f9a349a..0000000 --- a/org/apache/commons/net/chargen/CharGenUDPClient.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.chargen; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; - -import org.apache.commons.net.DatagramSocketClient; - -/*** - * The CharGenUDPClient class is a UDP implementation of a client for the - * character generator protocol described in RFC 864. It can also be - * used for Systat (RFC 866), Quote of the Day (RFC 865), and netstat - * (port 15). All of these protocols involve sending a datagram to the - * appropriate port, and reading data contained in one or more reply - * datagrams. The chargen and quote of the day protocols only send - * one reply datagram containing 512 bytes or less of data. The other - * protocols may reply with more than one datagram, in which case you - * must wait for a timeout to determine that all reply datagrams have - * been sent. - *

- * To use the CharGenUDPClient class, just open a local UDP port - * with {@link org.apache.commons.net.DatagramSocketClient#open open } - * and call {@link #send send } to send the datagram that will - * initiate the data reply. For chargen or quote of the day, just - * call {@link #receive receive }, and you're done. For netstat and - * systat, call receive in a while loop, and catch a SocketException and - * InterruptedIOException to detect a timeout (don't forget to set the - * timeout duration beforehand). Don't forget to call - * {@link org.apache.commons.net.DatagramSocketClient#close close() } - * to clean up properly. - *

- *

- * @author Daniel F. Savarese - * @see CharGenTCPClient - ***/ - -public final class CharGenUDPClient extends DatagramSocketClient -{ - /*** The systat port value of 11 according to RFC 866. ***/ - public static final int SYSTAT_PORT = 11; - /*** The netstat port value of 19. ***/ - public static final int NETSTAT_PORT = 15; - /*** The quote of the day port value of 17 according to RFC 865. ***/ - public static final int QUOTE_OF_DAY_PORT = 17; - /*** The character generator port value of 19 according to RFC 864. ***/ - public static final int CHARGEN_PORT = 19; - /*** The default chargen port. It is set to 19 according to RFC 864. ***/ - public static final int DEFAULT_PORT = 19; - - private byte[] __receiveData; - private DatagramPacket __receivePacket; - private DatagramPacket __sendPacket; - - /*** - * The default CharGenUDPClient constructor. It initializes some internal - * data structures for sending and receiving the necessary datagrams for - * the chargen and related protocols. - ***/ - public CharGenUDPClient() - { - // CharGen return packets have a maximum length of 512 - __receiveData = new byte[512]; - __receivePacket = new DatagramPacket(__receiveData, 512); - __sendPacket = new DatagramPacket(new byte[0], 0); - } - - - /*** - * Sends the data initiation datagram. This data in the packet is ignored - * by the server, and merely serves to signal that the server should send - * its reply. - *

- * @param host The address of the server. - * @param port The port of the service. - * @exception IOException If an error occurs while sending the datagram. - ***/ - public void send(InetAddress host, int port) throws IOException - { - __sendPacket.setAddress(host); - __sendPacket.setPort(port); - _socket_.send(__sendPacket); - } - - /*** Same as send(host, CharGenUDPClient.DEFAULT_PORT); ***/ - public void send(InetAddress host) throws IOException - { - send(host, DEFAULT_PORT); - } - - /*** - * Receive the reply data from the server. This will always be 512 bytes - * or less. Chargen and quote of the day only return one packet. Netstat - * and systat require multiple calls to receive() with timeout detection. - *

- * @return The reply data from the server. - * @exception IOException If an error occurs while receiving the datagram. - ***/ - public byte[] receive() throws IOException - { - int length; - byte[] result; - - _socket_.receive(__receivePacket); - - result = new byte[length = __receivePacket.getLength()]; - System.arraycopy(__receiveData, 0, result, 0, length); - - return result; - } - -} - diff --git a/org/apache/commons/net/daytime/DaytimeTCPClient.java b/org/apache/commons/net/daytime/DaytimeTCPClient.java deleted file mode 100644 index a77c8c1..0000000 --- a/org/apache/commons/net/daytime/DaytimeTCPClient.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.daytime; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -import org.apache.commons.net.SocketClient; - -/*** - * The DaytimeTCPClient class is a TCP implementation of a client for the - * Daytime protocol described in RFC 867. To use the class, merely - * establish a connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * and call {@link #getTime getTime() } to retrieve the daytime - * string, then - * call {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to close the connection properly. - *

- *

- * @author Daniel F. Savarese - * @see DaytimeUDPClient - ***/ - -public final class DaytimeTCPClient extends SocketClient -{ - /*** The default daytime port. It is set to 13 according to RFC 867. ***/ - public static final int DEFAULT_PORT = 13; - - // Received dates will likely be less than 64 characters. - // This is a temporary buffer used while receiving data. - private char[] __buffer = new char[64]; - - /*** - * The default DaytimeTCPClient constructor. It merely sets the default - * port to DEFAULT_PORT . - ***/ - public DaytimeTCPClient () - { - setDefaultPort(DEFAULT_PORT); - } - - /*** - * Retrieves the time string from the server and returns it. The - * server will have closed the connection at this point, so you should - * call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after calling this method. To retrieve another time, you must - * initiate another connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before calling getTime() again. - *

- * @return The time string retrieved from the server. - * @exception IOException If an error occurs while fetching the time string. - ***/ - public String getTime() throws IOException - { - int read; - StringBuffer result = new StringBuffer(__buffer.length); - BufferedReader reader; - - reader = new BufferedReader(new InputStreamReader(_input_)); - - while (true) - { - read = reader.read(__buffer, 0, __buffer.length); - if (read <= 0) - break; - result.append(__buffer, 0, read); - } - - return result.toString(); - } - -} - diff --git a/org/apache/commons/net/daytime/DaytimeUDPClient.java b/org/apache/commons/net/daytime/DaytimeUDPClient.java deleted file mode 100644 index 64eef9d..0000000 --- a/org/apache/commons/net/daytime/DaytimeUDPClient.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.daytime; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; - -import org.apache.commons.net.DatagramSocketClient; - -/*** - * The DaytimeUDPClient class is a UDP implementation of a client for the - * Daytime protocol described in RFC 867. To use the class, merely - * open a local datagram socket with - * {@link org.apache.commons.net.DatagramSocketClient#open open } - * and call {@link #getTime getTime } to retrieve the daytime - * string, then - * call {@link org.apache.commons.net.DatagramSocketClient#close close } - * to close the connection properly. Unlike - * {@link org.apache.commons.net.daytime.DaytimeTCPClient}, - * successive calls to {@link #getTime getTime } are permitted - * without re-establishing a connection. That is because UDP is a - * connectionless protocol and the Daytime protocol is stateless. - *

- *

- * @author Daniel F. Savarese - * @see DaytimeTCPClient - ***/ - -public final class DaytimeUDPClient extends DatagramSocketClient -{ - /*** The default daytime port. It is set to 13 according to RFC 867. ***/ - public static final int DEFAULT_PORT = 13; - - private byte[] __dummyData = new byte[1]; - // Received dates should be less than 256 bytes - private byte[] __timeData = new byte[256]; - - /*** - * Retrieves the time string from the specified server and port and - * returns it. - *

- * @param host The address of the server. - * @param port The port of the service. - * @return The time string. - * @exception IOException If an error occurs while retrieving the time. - ***/ - public String getTime(InetAddress host, int port) throws IOException - { - DatagramPacket sendPacket, receivePacket; - - sendPacket = - new DatagramPacket(__dummyData, __dummyData.length, host, port); - receivePacket = new DatagramPacket(__timeData, __timeData.length); - - _socket_.send(sendPacket); - _socket_.receive(receivePacket); - - return new String(receivePacket.getData(), 0, receivePacket.getLength()); - } - - /*** Same as getTime(host, DaytimeUDPClient.DEFAULT_PORT); ***/ - public String getTime(InetAddress host) throws IOException - { - return getTime(host, DEFAULT_PORT); - } - -} - diff --git a/org/apache/commons/net/discard/DiscardTCPClient.java b/org/apache/commons/net/discard/DiscardTCPClient.java deleted file mode 100644 index 7a771c9..0000000 --- a/org/apache/commons/net/discard/DiscardTCPClient.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.discard; - -import java.io.OutputStream; - -import org.apache.commons.net.SocketClient; - -/*** - * The DiscardTCPClient class is a TCP implementation of a client for the - * Discard protocol described in RFC 863. To use the class, merely - * establish a connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * and call {@link #getOutputStream getOutputStream() } to - * retrieve the discard output stream. Don't close the output stream - * when you're done writing to it. Rather, call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to clean up properly. - *

- *

- * @author Daniel F. Savarese - * @see DiscardUDPClient - ***/ - -public class DiscardTCPClient extends SocketClient -{ - /*** The default discard port. It is set to 9 according to RFC 863. ***/ - public static final int DEFAULT_PORT = 9; - - /*** - * The default DiscardTCPClient constructor. It merely sets the default - * port to DEFAULT_PORT . - ***/ - public DiscardTCPClient () - { - setDefaultPort(DEFAULT_PORT); - } - - /*** - * Returns an OutputStream through which you may write data to the server. - * You should NOT close the OutputStream when you're finished - * reading from it. Rather, you should call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to clean up properly. - *

- * @return An OutputStream through which you can write data to the server. - ***/ - public OutputStream getOutputStream() - { - return _output_; - } -} diff --git a/org/apache/commons/net/discard/DiscardUDPClient.java b/org/apache/commons/net/discard/DiscardUDPClient.java deleted file mode 100644 index a81b955..0000000 --- a/org/apache/commons/net/discard/DiscardUDPClient.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.discard; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; - -import org.apache.commons.net.DatagramSocketClient; - -/*** - * The DiscardUDPClient class is a UDP implementation of a client for the - * Discard protocol described in RFC 863. To use the class, - * just open a local UDP port - * with {@link org.apache.commons.net.DatagramSocketClient#open open } - * and call {@link #send send } to send datagrams to the server - * After you're done sending discard data, call - * {@link org.apache.commons.net.DatagramSocketClient#close close() } - * to clean up properly. - *

- *

- * @author Daniel F. Savarese - * @see DiscardTCPClient - ***/ - -public class DiscardUDPClient extends DatagramSocketClient -{ - /*** The default discard port. It is set to 9 according to RFC 863. ***/ - public static final int DEFAULT_PORT = 9; - - DatagramPacket _sendPacket; - - public DiscardUDPClient() - { - _sendPacket = new DatagramPacket(new byte[0], 0); - } - - - /*** - * Sends the specified data to the specified server at the specified port. - *

- * @param data The discard data to send. - * @param length The length of the data to send. Should be less than - * or equal to the length of the data byte array. - * @param host The address of the server. - * @param port The service port. - * @exception IOException If an error occurs during the datagram send - * operation. - ***/ - public void send(byte[] data, int length, InetAddress host, int port) - throws IOException - { - _sendPacket.setData(data); - _sendPacket.setLength(length); - _sendPacket.setAddress(host); - _sendPacket.setPort(port); - _socket_.send(_sendPacket); - } - - - /*** - * Same as - * send(data, length, host. DiscardUDPClient.DEFAULT_PORT). - ***/ - public void send(byte[] data, int length, InetAddress host) - throws IOException - { - send(data, length, host, DEFAULT_PORT); - } - - - /*** - * Same as - * send(data, data.length, host. DiscardUDPClient.DEFAULT_PORT). - ***/ - public void send(byte[] data, InetAddress host) throws IOException - { - send(data, data.length, host, DEFAULT_PORT); - } - -} - diff --git a/org/apache/commons/net/echo/EchoTCPClient.java b/org/apache/commons/net/echo/EchoTCPClient.java deleted file mode 100644 index b4d43e2..0000000 --- a/org/apache/commons/net/echo/EchoTCPClient.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.echo; - -import java.io.InputStream; - -import org.apache.commons.net.discard.DiscardTCPClient; - -/*** - * The EchoTCPClient class is a TCP implementation of a client for the - * Echo protocol described in RFC 862. To use the class, merely - * establish a connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * and call {@link DiscardTCPClient#getOutputStream getOutputStream() } to - * retrieve the echo output stream and - * {@link #getInputStream getInputStream() } - * to get the echo input stream. - * Don't close either stream when you're done using them. Rather, call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to clean up properly. - *

- *

- * @author Daniel F. Savarese - * @see EchoUDPClient - * @see DiscardTCPClient - ***/ - -public final class EchoTCPClient extends DiscardTCPClient -{ - /*** The default echo port. It is set to 7 according to RFC 862. ***/ - public static final int DEFAULT_PORT = 7; - - /*** - * The default EchoTCPClient constructor. It merely sets the default - * port to DEFAULT_PORT . - ***/ - public EchoTCPClient () - { - setDefaultPort(DEFAULT_PORT); - } - - /*** - * Returns an InputStream from which you may read echoed data from - * the server. You should NOT close the InputStream when you're finished - * reading from it. Rather, you should call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to clean up properly. - *

- * @return An InputStream from which you can read echoed data from the - * server. - ***/ - public InputStream getInputStream() - { - return _input_; - } - -} diff --git a/org/apache/commons/net/echo/EchoUDPClient.java b/org/apache/commons/net/echo/EchoUDPClient.java deleted file mode 100644 index 70a4898..0000000 --- a/org/apache/commons/net/echo/EchoUDPClient.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.echo; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; - -import org.apache.commons.net.discard.DiscardUDPClient; - -/*** - * The EchoUDPClient class is a UDP implementation of a client for the - * Echo protocol described in RFC 862. To use the class, - * just open a local UDP port - * with {@link org.apache.commons.net.DatagramSocketClient#open open } - * and call {@link #send send } to send datagrams to the server, - * then call {@link #receive receive } to receive echoes. - * After you're done echoing data, call - * {@link org.apache.commons.net.DatagramSocketClient#close close() } - * to clean up properly. - *

- *

- * @author Daniel F. Savarese - * @see EchoTCPClient - * @see DiscardUDPClient - ***/ - -public final class EchoUDPClient extends DiscardUDPClient -{ - /*** The default echo port. It is set to 7 according to RFC 862. ***/ - public static final int DEFAULT_PORT = 7; - - private DatagramPacket __receivePacket = new DatagramPacket(new byte[0], 0); - - /*** - * Sends the specified data to the specified server at the default echo - * port. - *

- * @param data The echo data to send. - * @param length The length of the data to send. Should be less than - * or equal to the length of the data byte array. - * @param host The address of the server. - * @exception IOException If an error occurs during the datagram send - * operation. - ***/ - @Override - public void send(byte[] data, int length, InetAddress host) - throws IOException - { - send(data, length, host, DEFAULT_PORT); - } - - - /*** Same as send(data, data.length, host) ***/ - @Override - public void send(byte[] data, InetAddress host) throws IOException - { - send(data, data.length, host, DEFAULT_PORT); - } - - - /*** - * Receives echoed data and returns its length. The data may be divided - * up among multiple datagrams, requiring multiple calls to receive. - * Also, the UDP packets will not necessarily arrive in the same order - * they were sent. - *

- * @return Length of actual data received. - * @exception IOException If an error occurs while receiving the data. - ***/ - public int receive(byte[] data, int length) throws IOException - { - __receivePacket.setData(data); - __receivePacket.setLength(length); - _socket_.receive(__receivePacket); - return __receivePacket.getLength(); - } - - /*** Same as receive(data, data.length) ***/ - public int receive(byte[] data) throws IOException - { - return receive(data, data.length); - } - -} - diff --git a/org/apache/commons/net/finger/FingerClient.java b/org/apache/commons/net/finger/FingerClient.java deleted file mode 100644 index d3b6893..0000000 --- a/org/apache/commons/net/finger/FingerClient.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.net.finger; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; - -import org.apache.commons.net.SocketClient; - -/*** - * The FingerClient class implements the client side of the Internet Finger - * Protocol defined in RFC 1288. To finger a host you create a - * FingerClient instance, connect to the host, query the host, and finally - * disconnect from the host. If the finger service you want to query is on - * a non-standard port, connect to the host at that port. - * Here's a sample use: - *

- *    FingerClient finger;
- *
- *    finger = new FingerClient();
- *
- *    try {
- *      finger.connect("foo.bar.com");
- *      System.out.println(finger.query("foobar", false));
- *      finger.disconnect();
- *    } catch(IOException e) {
- *      System.err.println("Error I/O exception: " + e.getMessage());
- *      return;
- *    }
- * 
- *

- *

- * @author Daniel F. Savarese - ***/ - -public class FingerClient extends SocketClient -{ - /*** - * The default FINGER port. Set to 79 according to RFC 1288. - ***/ - public static final int DEFAULT_PORT = 79; - - private static final String __LONG_FLAG = "/W "; - - private transient StringBuffer __query = new StringBuffer(64); - private transient char[] __buffer = new char[1024]; - - /*** - * The default FingerClient constructor. Initializes the - * default port to DEFAULT_PORT . - ***/ - public FingerClient() - { - setDefaultPort(DEFAULT_PORT); - } - - - /*** - * Fingers a user at the connected host and returns the output - * as a String. You must first connect to a finger server before - * calling this method, and you should disconnect afterward. - *

- * @param longOutput Set to true if long output is requested, false if not. - * @param username The name of the user to finger. - * @return The result of the finger query. - * @exception IOException If an I/O error occurs while reading the socket. - ***/ - public String query(boolean longOutput, String username) throws IOException - { - int read; - StringBuffer result = new StringBuffer(__buffer.length); - BufferedReader input; - - input = - new BufferedReader(new InputStreamReader(getInputStream(longOutput, - username))); - - while (true) - { - read = input.read(__buffer, 0, __buffer.length); - if (read <= 0) - break; - result.append(__buffer, 0, read); - } - - input.close(); - - return result.toString(); - } - - - /*** - * Fingers the connected host and returns the output - * as a String. You must first connect to a finger server before - * calling this method, and you should disconnect afterward. - * This is equivalent to calling query(longOutput, "") . - *

- * @param longOutput Set to true if long output is requested, false if not. - * @return The result of the finger query. - * @exception IOException If an I/O error occurs while reading the socket. - ***/ - public String query(boolean longOutput) throws IOException - { - return query(longOutput, ""); - } - - - /*** - * Fingers a user and returns the input stream from the network connection - * of the finger query. You must first connect to a finger server before - * calling this method, and you should disconnect after finishing reading - * the stream. - *

- * @param longOutput Set to true if long output is requested, false if not. - * @param username The name of the user to finger. - * @return The InputStream of the network connection of the finger query. - * Can be read to obtain finger results. - * @exception IOException If an I/O error during the operation. - ***/ - public InputStream getInputStream(boolean longOutput, String username) - throws IOException - { - return getInputStream(longOutput, username, null); - } - - /*** - * Fingers a user and returns the input stream from the network connection - * of the finger query. You must first connect to a finger server before - * calling this method, and you should disconnect after finishing reading - * the stream. - *

- * @param longOutput Set to true if long output is requested, false if not. - * @param username The name of the user to finger. - * @param encoding the character encoding that should be used for the query, - * null for the platform's default encoding - * @return The InputStream of the network connection of the finger query. - * Can be read to obtain finger results. - * @exception IOException If an I/O error during the operation. - ***/ - public InputStream getInputStream(boolean longOutput, String username, String encoding) - throws IOException - { - DataOutputStream output; - - __query.setLength(0); - if (longOutput) - __query.append(__LONG_FLAG); - __query.append(username); - __query.append(SocketClient.NETASCII_EOL); - - byte[] encodedQuery = - (encoding == null ? __query.toString().getBytes() : __query.toString().getBytes(encoding)); - - output = new DataOutputStream(new BufferedOutputStream(_output_, 1024)); - output.write(encodedQuery, 0, encodedQuery.length); - output.flush(); - - return _input_; - } - - - /*** - * Fingers the connected host and returns the input stream from - * the network connection of the finger query. This is equivalent to - * calling getInputStream(longOutput, ""). You must first connect to a - * finger server before calling this method, and you should disconnect - * after finishing reading the stream. - *

- * @param longOutput Set to true if long output is requested, false if not. - * @return The InputStream of the network connection of the finger query. - * Can be read to obtain finger results. - * @exception IOException If an I/O error during the operation. - ***/ - public InputStream getInputStream(boolean longOutput) throws IOException - { - return getInputStream(longOutput, ""); - } - -} diff --git a/org/apache/commons/net/ftp/Configurable.class b/org/apache/commons/net/ftp/Configurable.class deleted file mode 100644 index abcae1f..0000000 Binary files a/org/apache/commons/net/ftp/Configurable.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/Configurable.java b/org/apache/commons/net/ftp/Configurable.java deleted file mode 100644 index 5e8e749..0000000 --- a/org/apache/commons/net/ftp/Configurable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - - -/** - * This interface adds the aspect of configurability by means of - * a supplied FTPClientConfig object to other classes in the - * system, especially listing parsers. - */ -public interface Configurable { - - /** - * @param config the object containing the configuration data - * @throws IllegalArgumentException if the elements of the - * config are somehow inadequate to configure the - * Configurable object. - */ - public void configure(FTPClientConfig config); -} diff --git a/org/apache/commons/net/ftp/FTP.class b/org/apache/commons/net/ftp/FTP.class deleted file mode 100644 index a363d55..0000000 Binary files a/org/apache/commons/net/ftp/FTP.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTP.java b/org/apache/commons/net/ftp/FTP.java deleted file mode 100644 index 6e2eff8..0000000 --- a/org/apache/commons/net/ftp/FTP.java +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Arrays; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandListener; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; - -/*** - * FTP provides the basic the functionality necessary to implement your - * own FTP client. It extends org.apache.commons.net.SocketClient since - * extending TelnetClient was causing unwanted behavior (like connections - * that did not time out properly). - *

- * To derive the full benefits of the FTP class requires some knowledge - * of the FTP protocol defined in RFC 959. However, there is no reason - * why you should have to use the FTP class. The - * {@link org.apache.commons.net.ftp.FTPClient} class, - * derived from FTP, - * implements all the functionality required of an FTP client. The - * FTP class is made public to provide access to various FTP constants - * and to make it easier for adventurous programmers (or those with - * special needs) to interact with the FTP protocol and implement their - * own clients. A set of methods with names corresponding to the FTP - * command names are provided to facilitate this interaction. - *

- * You should keep in mind that the FTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period (usually 900 seconds). The FTP class will detect a - * premature FTP server connection closing when it receives a - * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the FTP class method encountering that reply will throw - * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * . FTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by FTP. Before disconnecting, you may check the - * last reply code and text with - * {@link #getReplyCode getReplyCode }, - * {@link #getReplyString getReplyString }, - * and {@link #getReplyStrings getReplyStrings}. - * You may avoid server disconnections while the client is idle by - * periodicaly sending NOOP commands to the server. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @author Rory Winston - * @author Joseph Hindsley - * @see FTPClient - * @see FTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - * @version $Id: FTP.java 658520 2008-05-21 01:14:11Z sebb $ - ***/ - -public class FTP extends SocketClient -{ - /*** The default FTP data port (20). ***/ - public static final int DEFAULT_DATA_PORT = 20; - /*** The default FTP control port (21). ***/ - public static final int DEFAULT_PORT = 21; - - /*** - * A constant used to indicate the file(s) being transfered should - * be treated as ASCII. This is the default file type. All constants - * ending in FILE_TYPE are used to indicate file types. - ***/ - public static final int ASCII_FILE_TYPE = 0; - - /*** - * A constant used to indicate the file(s) being transfered should - * be treated as EBCDIC. Note however that there are several different - * EBCDIC formats. All constants ending in FILE_TYPE - * are used to indicate file types. - ***/ - public static final int EBCDIC_FILE_TYPE = 1; - - - /*** - * A constant used to indicate the file(s) being transfered should - * be treated as a binary image, i.e., no translations should be - * performed. All constants ending in FILE_TYPE are used to - * indicate file types. - ***/ - public static final int BINARY_FILE_TYPE = 2; - - /*** - * A constant used to indicate the file(s) being transfered should - * be treated as a local type. All constants ending in - * FILE_TYPE are used to indicate file types. - ***/ - public static final int LOCAL_FILE_TYPE = 3; - - /*** - * A constant used for text files to indicate a non-print text format. - * This is the default format. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - ***/ - public static final int NON_PRINT_TEXT_FORMAT = 4; - - /*** - * A constant used to indicate a text file contains format vertical format - * control characters. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - ***/ - public static final int TELNET_TEXT_FORMAT = 5; - - /*** - * A constant used to indicate a text file contains ASA vertical format - * control characters. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - ***/ - public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6; - - /*** - * A constant used to indicate a file is to be treated as a continuous - * sequence of bytes. This is the default structure. All constants ending - * in _STRUCTURE are used to indicate file structure for - * file transfers. - ***/ - public static final int FILE_STRUCTURE = 7; - - /*** - * A constant used to indicate a file is to be treated as a sequence - * of records. All constants ending in _STRUCTURE - * are used to indicate file structure for file transfers. - ***/ - public static final int RECORD_STRUCTURE = 8; - - /*** - * A constant used to indicate a file is to be treated as a set of - * independent indexed pages. All constants ending in - * _STRUCTURE are used to indicate file structure for file - * transfers. - ***/ - public static final int PAGE_STRUCTURE = 9; - - /*** - * A constant used to indicate a file is to be transfered as a stream - * of bytes. This is the default transfer mode. All constants ending - * in TRANSFER_MODE are used to indicate file transfer - * modes. - ***/ - public static final int STREAM_TRANSFER_MODE = 10; - - /*** - * A constant used to indicate a file is to be transfered as a series - * of blocks. All constants ending in TRANSFER_MODE are used - * to indicate file transfer modes. - ***/ - public static final int BLOCK_TRANSFER_MODE = 11; - - /*** - * A constant used to indicate a file is to be transfered as FTP - * compressed data. All constants ending in TRANSFER_MODE - * are used to indicate file transfer modes. - ***/ - public static final int COMPRESSED_TRANSFER_MODE = 12; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - /** - * The default character encoding used for communicating over an - * FTP control connection. The default encoding is an - * ASCII-compatible encoding. Some FTP servers expect other - * encodings. You can change the encoding used by an FTP instance - * with {@link #setControlEncoding setControlEncoding}. - */ - public static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1"; - private static final String __modes = "AEILNTCFRPSBC"; - - private StringBuilder __commandBuffer = new StringBuilder(); - - protected int _replyCode; - protected ArrayList _replyLines; - protected boolean _newReplyString; - protected String _replyString; - protected String _controlEncoding; - - /** - * This is used to signal whether a block of multiline responses beginning - * with xxx must be terminated by the same numeric code xxx - * See section 4.2 of RFX 959 for details. - */ - protected boolean strictMultilineParsing = false; - - /** - * Wraps SocketClient._input_ to facilitate the writing of text - * to the FTP control connection. Do not access the control - * connection via SocketClient._input_. This member starts - * with a null value, is initialized in {@link #_connectAction_}, - * and set to null in {@link #disconnect}. - */ - protected BufferedReader _controlInput_; - - /** - * Wraps SocketClient._output_ to facilitate the reading of text - * from the FTP control connection. Do not access the control - * connection via SocketClient._output_. This member starts - * with a null value, is initialized in {@link #_connectAction_}, - * and set to null in {@link #disconnect}. - */ - protected BufferedWriter _controlOutput_; - - /*** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and te firing of ProtocolCommandEvents. - ***/ - protected ProtocolCommandSupport _commandSupport_; - - /*** - * The default FTP constructor. Sets the default port to - * DEFAULT_PORT and initializes internal data structures - * for saving FTP reply information. - ***/ - public FTP() - { - super(); - setDefaultPort(DEFAULT_PORT); - _replyLines = new ArrayList(); - _newReplyString = false; - _replyString = null; - _commandSupport_ = new ProtocolCommandSupport(this); - _controlEncoding = DEFAULT_CONTROL_ENCODING; - } - - // The RFC-compliant multiline termination check - private boolean __strictCheck(String line, String code) { - return (!(line.startsWith(code) && line.charAt(3) == ' ')); - } - - // The strict check is too strong a condition because of non-conforming ftp - // servers like ftp.funet.fi which sent 226 as the last line of a - // 426 multi-line reply in response to ls /. We relax the condition to - // test that the line starts with a digit rather than starting with - // the code. - private boolean __lenientCheck(String line) { - return (!(line.length() >= 4 && line.charAt(3) != '-' && - Character.isDigit(line.charAt(0)))); - } - - private void __getReply() throws IOException - { - int length; - - _newReplyString = true; - _replyLines.clear(); - - String line = _controlInput_.readLine(); - - if (line == null) - throw new FTPConnectionClosedException( - "Connection closed without indication."); - - // In case we run into an anomaly we don't want fatal index exceptions - // to be thrown. - length = line.length(); - if (length < 3) - throw new MalformedServerReplyException( - "Truncated server reply: " + line); - - String code = null; - try - { - code = line.substring(0, 3); - _replyCode = Integer.parseInt(code); - } - catch (NumberFormatException e) - { - throw new MalformedServerReplyException( - "Could not parse response code.\nServer Reply: " + line); - } - - _replyLines.add(line); - - // Get extra lines if message continues. - if (length > 3 && line.charAt(3) == '-') - { - do - { - line = _controlInput_.readLine(); - - if (line == null) - throw new FTPConnectionClosedException( - "Connection closed without indication."); - - _replyLines.add(line); - - // The length() check handles problems that could arise from readLine() - // returning too soon after encountering a naked CR or some other - // anomaly. - } - while ( isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line)); - } - - if (_commandSupport_.getListenerCount() > 0) { - _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); - } - - if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { - throw new FTPConnectionClosedException("FTP response 421 received. Server closed connection."); - } - } - - /** - * Initiates control connections and gets initial reply. - * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. - */ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - _controlInput_ = - new BufferedReader(new InputStreamReader(_socket_.getInputStream(), - getControlEncoding())); - _controlOutput_ = - new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), - getControlEncoding())); - __getReply(); - // If we received code 120, we have to fetch completion reply. - if (FTPReply.isPositivePreliminary(_replyCode)) - __getReply(); - } - - - /** - * Sets the character encoding used by the FTP control connection. - * Some FTP servers require that commands be issued in a non-ASCII - * encoding like UTF-8 so that filenames with multi-byte character - * representations (e.g, Big 8) can be specified. - * - * @param encoding The new character encoding for the control connection. - */ - public void setControlEncoding(String encoding) { - _controlEncoding = encoding; - } - - - /** - * @return The character encoding used to communicate over the - * control connection. - */ - public String getControlEncoding() { - return _controlEncoding; - } - - - /*** - * Adds a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to add. - ***/ - public void addProtocolCommandListener(ProtocolCommandListener listener) - { - _commandSupport_.addProtocolCommandListener(listener); - } - - /*** - * Removes a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to remove. - ***/ - public void removeProtocolCommandListener(ProtocolCommandListener listener) - { - _commandSupport_.removeProtocolCommandListener(listener); - } - - - /*** - * Closes the control connection to the FTP server and sets to null - * some internal data so that the memory may be reclaimed by the - * garbage collector. The reply text and code information from the - * last command is voided so that the memory it used may be reclaimed. - * Also sets {@link #_controlInput_} and {@link #_controlOutput_} to null. - *

- * @exception IOException If an error occurs while disconnecting. - ***/ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - _controlInput_ = null; - _controlOutput_ = null; - _newReplyString = false; - _replyString = null; - } - - - /*** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The text representation of the FTP command to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command, String args) throws IOException - { - String message; - - __commandBuffer.setLength(0); - __commandBuffer.append(command); - - if (args != null) - { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - - try{ - _controlOutput_.write(message = __commandBuffer.toString()); - _controlOutput_.flush(); - } - catch (SocketException e) - { - if (!isConnected() || !socketIsConnected(_socket_)) - { - throw new FTPConnectionClosedException("Connection unexpectedly closed."); - } - else - { - throw e; - } - } - - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireCommandSent(command, message); - - __getReply(); - return _replyCode; - } - - /** - * Checks if the socket is connected - * - * @param socket - * @return true if connected - */ - private boolean socketIsConnected(Socket socket) - { - if (socket == null) - { - return false; - } - - return socket.isConnected(); - - } - - /*** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The FTPCommand constant corresponding to the FTP command - * to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command, String args) throws IOException - { - return sendCommand(FTPCommand._commands[command], args); - } - - - /*** - * Sends an FTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The text representation of the FTP command to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command) throws IOException - { - return sendCommand(command, null); - } - - - /*** - * Sends an FTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The FTPCommand constant corresponding to the FTP command - * to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command) throws IOException - { - return sendCommand(command, null); - } - - - /*** - * Returns the integer value of the reply code of the last FTP reply. - * You will usually only use this method after you connect to the - * FTP server to check that the connection was successful since - * connect is of type void. - *

- * @return The integer value of the reply code of the last FTP reply. - ***/ - public int getReplyCode() - { - return _replyCode; - } - - /*** - * Fetches a reply from the FTP server and returns the integer reply - * code. After calling this method, the actual reply text can be accessed - * from either calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. Only use this - * method if you are implementing your own FTP client or if you need to - * fetch a secondary response from the FTP server. - *

- * @return The integer value of the reply code of the fetched FTP reply. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while receiving the - * server reply. - ***/ - public int getReply() throws IOException - { - __getReply(); - return _replyCode; - } - - - /*** - * Returns the lines of text from the last FTP server response as an array - * of strings, one entry per line. The end of line markers of each are - * stripped from each line. - *

- * @return The lines of text from the last FTP response as an array. - ***/ - public String[] getReplyStrings() - { - String[] lines; - lines = new String[_replyLines.size()]; - _replyLines.addAll(Arrays.asList(lines)); - return lines; - } - - /*** - * Returns the entire text of the last FTP server response exactly - * as it was received, including all end of line markers in NETASCII - * format. - *

- * @return The entire text from the last FTP response as a String. - ***/ - public String getReplyString() - { - StringBuilder buffer; - - if (!_newReplyString) { - return _replyString; - } - - buffer = new StringBuilder(256); - - for (String line : _replyLines) { - buffer.append(line); - buffer.append(SocketClient.NETASCII_EOL); - } - - _newReplyString = false; - - return (_replyString = buffer.toString()); - } - - - /*** - * A convenience method to send the FTP USER command to the server, - * receive the reply, and return the reply code. - *

- * @param username The username to login under. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int user(String username) throws IOException - { - return sendCommand(FTPCommand.USER, username); - } - - /** - * A convenience method to send the FTP PASS command to the server, - * receive the reply, and return the reply code. - * @param password The plain text password of the username being logged into. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int pass(String password) throws IOException - { - return sendCommand(FTPCommand.PASS, password); - } - - /*** - * A convenience method to send the FTP ACCT command to the server, - * receive the reply, and return the reply code. - *

- * @param account The account name to access. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int acct(String account) throws IOException - { - return sendCommand(FTPCommand.ACCT, account); - } - - - /*** - * A convenience method to send the FTP ABOR command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int abor() throws IOException - { - return sendCommand(FTPCommand.ABOR); - } - - /*** - * A convenience method to send the FTP CWD command to the server, - * receive the reply, and return the reply code. - *

- * @param directory The new working directory. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int cwd(String directory) throws IOException - { - return sendCommand(FTPCommand.CWD, directory); - } - - /*** - * A convenience method to send the FTP CDUP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int cdup() throws IOException - { - return sendCommand(FTPCommand.CDUP); - } - - /*** - * A convenience method to send the FTP QUIT command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int quit() throws IOException - { - return sendCommand(FTPCommand.QUIT); - } - - /*** - * A convenience method to send the FTP REIN command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rein() throws IOException - { - return sendCommand(FTPCommand.REIN); - } - - /*** - * A convenience method to send the FTP SMNT command to the server, - * receive the reply, and return the reply code. - *

- * @param dir The directory name. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int smnt(String dir) throws IOException - { - return sendCommand(FTPCommand.SMNT, dir); - } - - /*** - * A convenience method to send the FTP PORT command to the server, - * receive the reply, and return the reply code. - *

- * @param host The host owning the port. - * @param port The new port. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int port(InetAddress host, int port) throws IOException - { - int num; - StringBuffer info = new StringBuffer(24); - - info.append(host.getHostAddress().replace('.', ',')); - num = port >>> 8; - info.append(','); - info.append(num); - info.append(','); - num = port & 0xff; - info.append(num); - - return sendCommand(FTPCommand.PORT, info.toString()); - } - - /*** - * A convenience method to send the FTP PASV command to the server, - * receive the reply, and return the reply code. Remember, it's up - * to you to interpret the reply string containing the host/port - * information. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int pasv() throws IOException - { - return sendCommand(FTPCommand.PASV); - } - - /** - * A convenience method to send the FTP TYPE command for text files - * to the server, receive the reply, and return the reply code. - * @param fileType The type of the file (one of the FILE_TYPE - * constants). - * @param formatOrByteSize The format of the file (one of the - * _FORMAT constants. In the case of - * LOCAL_FILE_TYPE, the byte size. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int type(int fileType, int formatOrByteSize) throws IOException - { - StringBuffer arg = new StringBuffer(); - - arg.append(__modes.charAt(fileType)); - arg.append(' '); - if (fileType == LOCAL_FILE_TYPE) - arg.append(formatOrByteSize); - else - arg.append(__modes.charAt(formatOrByteSize)); - - return sendCommand(FTPCommand.TYPE, arg.toString()); - } - - - /** - * A convenience method to send the FTP TYPE command to the server, - * receive the reply, and return the reply code. - *

- * @param fileType The type of the file (one of the FILE_TYPE - * constants). - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int type(int fileType) throws IOException - { - return sendCommand(FTPCommand.TYPE, - __modes.substring(fileType, fileType + 1)); - } - - /*** - * A convenience method to send the FTP STRU command to the server, - * receive the reply, and return the reply code. - *

- * @param structure The structure of the file (one of the - * _STRUCTURE constants). - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stru(int structure) throws IOException - { - return sendCommand(FTPCommand.STRU, - __modes.substring(structure, structure + 1)); - } - - /*** - * A convenience method to send the FTP MODE command to the server, - * receive the reply, and return the reply code. - *

- * @param mode The transfer mode to use (one of the - * TRANSFER_MODE constants). - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int mode(int mode) throws IOException - { - return sendCommand(FTPCommand.MODE, - __modes.substring(mode, mode + 1)); - } - - /*** - * A convenience method to send the FTP RETR command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @param pathname The pathname of the file to retrieve. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int retr(String pathname) throws IOException - { - return sendCommand(FTPCommand.RETR, pathname); - } - - /*** - * A convenience method to send the FTP STOR command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @param pathname The pathname to use for the file when stored at - * the remote end of the transfer. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stor(String pathname) throws IOException - { - return sendCommand(FTPCommand.STOR, pathname); - } - - /*** - * A convenience method to send the FTP STOU command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stou() throws IOException - { - return sendCommand(FTPCommand.STOU); - } - - /*** - * A convenience method to send the FTP STOU command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * @param pathname The base pathname to use for the file when stored at - * the remote end of the transfer. Some FTP servers - * require this. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stou(String pathname) throws IOException - { - return sendCommand(FTPCommand.STOU, pathname); - } - - /*** - * A convenience method to send the FTP APPE command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @param pathname The pathname to use for the file when stored at - * the remote end of the transfer. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int appe(String pathname) throws IOException - { - return sendCommand(FTPCommand.APPE, pathname); - } - - /*** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - *

- * @param bytes The number of bytes to allocate. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int allo(int bytes) throws IOException - { - return sendCommand(FTPCommand.ALLO, Integer.toString(bytes)); - } - - /*** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - *

- * @param bytes The number of bytes to allocate. - * @param recordSize The size of a record. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int allo(int bytes, int recordSize) throws IOException - { - return sendCommand(FTPCommand.ALLO, Integer.toString(bytes) + " R " + - Integer.toString(recordSize)); - } - - /*** - * A convenience method to send the FTP REST command to the server, - * receive the reply, and return the reply code. - *

- * @param marker The marker at which to restart a transfer. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rest(String marker) throws IOException - { - return sendCommand(FTPCommand.REST, marker); - } - - - /** - * @since 2.0 - **/ - public int mdtm(String file) throws IOException - { - return sendCommand(FTPCommand.MDTM, file); - } - - /*** - * A convenience method to send the FTP RNFR command to the server, - * receive the reply, and return the reply code. - *

- * @param pathname The pathname to rename from. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rnfr(String pathname) throws IOException - { - return sendCommand(FTPCommand.RNFR, pathname); - } - - /*** - * A convenience method to send the FTP RNTO command to the server, - * receive the reply, and return the reply code. - *

- * @param pathname The pathname to rename to - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rnto(String pathname) throws IOException - { - return sendCommand(FTPCommand.RNTO, pathname); - } - - /*** - * A convenience method to send the FTP DELE command to the server, - * receive the reply, and return the reply code. - *

- * @param pathname The pathname to delete. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int dele(String pathname) throws IOException - { - return sendCommand(FTPCommand.DELE, pathname); - } - - /*** - * A convenience method to send the FTP RMD command to the server, - * receive the reply, and return the reply code. - *

- * @param pathname The pathname of the directory to remove. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rmd(String pathname) throws IOException - { - return sendCommand(FTPCommand.RMD, pathname); - } - - /*** - * A convenience method to send the FTP MKD command to the server, - * receive the reply, and return the reply code. - *

- * @param pathname The pathname of the new directory to create. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int mkd(String pathname) throws IOException - { - return sendCommand(FTPCommand.MKD, pathname); - } - - /*** - * A convenience method to send the FTP PWD command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int pwd() throws IOException - { - return sendCommand(FTPCommand.PWD); - } - - /*** - * A convenience method to send the FTP LIST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int list() throws IOException - { - return sendCommand(FTPCommand.LIST); - } - - /*** - * A convenience method to send the FTP LIST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @param pathname The pathname to list. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int list(String pathname) throws IOException - { - return sendCommand(FTPCommand.LIST, pathname); - } - - /*** - * A convenience method to send the FTP NLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int nlst() throws IOException - { - return sendCommand(FTPCommand.NLST); - } - - /*** - * A convenience method to send the FTP NLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - *

- * @param pathname The pathname to list. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int nlst(String pathname) throws IOException - { - return sendCommand(FTPCommand.NLST, pathname); - } - - /*** - * A convenience method to send the FTP SITE command to the server, - * receive the reply, and return the reply code. - *

- * @param parameters The site parameters to send. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int site(String parameters) throws IOException - { - return sendCommand(FTPCommand.SITE, parameters); - } - - /*** - * A convenience method to send the FTP SYST command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int syst() throws IOException - { - return sendCommand(FTPCommand.SYST); - } - - /*** - * A convenience method to send the FTP STAT command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat() throws IOException - { - return sendCommand(FTPCommand.STAT); - } - - /*** - * A convenience method to send the FTP STAT command to the server, - * receive the reply, and return the reply code. - *

- * @param pathname A pathname to list. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat(String pathname) throws IOException - { - return sendCommand(FTPCommand.STAT, pathname); - } - - /*** - * A convenience method to send the FTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help() throws IOException - { - return sendCommand(FTPCommand.HELP); - } - - /*** - * A convenience method to send the FTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @param command The command name on which to request help. - * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help(String command) throws IOException - { - return sendCommand(FTPCommand.HELP, command); - } - - /*** - * A convenience method to send the FTP NOOP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int noop() throws IOException - { - return sendCommand(FTPCommand.NOOP); - } - - /** - * Return whether strict multiline parsing is enabled, as per RFX 959, section 4.2. - * @return True if strict, false if lenient - * @since 2.0 - */ - public boolean isStrictMultilineParsing() { - return strictMultilineParsing; - } - - /** - * Set strict multiline parsing. - * @param strictMultilineParsing - * @since 2.0 - */ - public void setStrictMultilineParsing(boolean strictMultilineParsing) { - this.strictMultilineParsing = strictMultilineParsing; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/ftp/FTPClient.class b/org/apache/commons/net/ftp/FTPClient.class deleted file mode 100644 index 60ac793..0000000 Binary files a/org/apache/commons/net/ftp/FTPClient.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPClient.java b/org/apache/commons/net/ftp/FTPClient.java deleted file mode 100644 index 9a2c459..0000000 --- a/org/apache/commons/net/ftp/FTPClient.java +++ /dev/null @@ -1,2447 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.ArrayList; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory; -import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory; -import org.apache.commons.net.ftp.parser.ParserInitializationException; -import org.apache.commons.net.io.CopyStreamEvent; -import org.apache.commons.net.io.CopyStreamException; -import org.apache.commons.net.io.FromNetASCIIInputStream; -import org.apache.commons.net.io.ToNetASCIIOutputStream; -import org.apache.commons.net.io.Util; - -/*** - * FTPClient encapsulates all the functionality necessary to store and - * retrieve files from an FTP server. This class takes care of all - * low level details of interacting with an FTP server and provides - * a convenient higher level interface. As with all classes derived - * from {@link org.apache.commons.net.SocketClient}, - * you must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before doing anything, and finally - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after you're completely finished interacting with the server. - * Then you need to check the FTP reply code to see if the connection - * was successful. For example: - *

- *    boolean error = false;
- *    try {
- *      int reply;
- *      ftp.connect("ftp.foobar.com");
- *      System.out.println("Connected to " + server + ".");
- *      System.out.print(ftp.getReplyString());
- *
- *      // After connection attempt, you should check the reply code to verify
- *      // success.
- *      reply = ftp.getReplyCode();
- *
- *      if(!FTPReply.isPositiveCompletion(reply)) {
- *        ftp.disconnect();
- *        System.err.println("FTP server refused connection.");
- *        System.exit(1);
- *      }
- *      ... // transfer files
- *      ftp.logout();
- *    } catch(IOException e) {
- *      error = true;
- *      e.printStackTrace();
- *    } finally {
- *      if(ftp.isConnected()) {
- *        try {
- *          ftp.disconnect();
- *        } catch(IOException ioe) {
- *          // do nothing
- *        }
- *      }
- *      System.exit(error ? 1 : 0);
- *    }
- * 
- *

- * Immediately after connecting is the only real time you need to check the - * reply code (because connect is of type void). The convention for all the - * FTP command methods in FTPClient is such that they either return a - * boolean value or some other value. - * The boolean methods return true on a successful completion reply from - * the FTP server and false on a reply resulting in an error condition or - * failure. The methods returning a value other than boolean return a value - * containing the higher level data produced by the FTP command, or null if a - * reply resulted in an error condition or failure. If you want to access - * the exact FTP reply code causing a success or failure, you must call - * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after - * a success or failure. - *

- * The default settings for FTPClient are for it to use - * FTP.ASCII_FILE_TYPE , - * FTP.NON_PRINT_TEXT_FORMAT , - * FTP.STREAM_TRANSFER_MODE , and - * FTP.FILE_STRUCTURE . The only file types directly supported - * are FTP.ASCII_FILE_TYPE and - * FTP.BINARY_FILE_TYPE . Because there are at least 4 - * different EBCDIC encodings, we have opted not to provide direct support - * for EBCDIC. To transfer EBCDIC and other unsupported file types you - * must create your own filter InputStreams and OutputStreams and wrap - * them around the streams returned or required by the FTPClient methods. - * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII} - * filter streams to provide transparent handling of ASCII files. We will - * consider incorporating EBCDIC support if there is enough demand. - *

- * FTP.NON_PRINT_TEXT_FORMAT , - * FTP.STREAM_TRANSFER_MODE , and - * FTP.FILE_STRUCTURE are the only supported formats, - * transfer modes, and file structures. - *

- * Because the handling of sockets on different platforms can differ - * significantly, the FTPClient automatically issues a new PORT command - * prior to every transfer requiring that the server connect to the client's - * data port. This ensures identical problem-free behavior on Windows, Unix, - * and Macintosh platforms. Additionally, it relieves programmers from - * having to issue the PORT command themselves and dealing with platform - * dependent issues. - *

- * Additionally, for security purposes, all data connections to the - * client are verified to ensure that they originated from the intended - * party (host and port). If a data connection is initiated by an unexpected - * party, the command will close the socket and throw an IOException. You - * may disable this behavior with - * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}. - *

- * You should keep in mind that the FTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period (usually 900 seconds). The FTPClient class will detect a - * premature FTP server connection closing when it receives a - * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the FTP class method encountering that reply will throw - * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * . - * FTPConnectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by FTPClient. Before disconnecting, you may check the - * last reply code and text with - * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode }, - * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString }, - * and - * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}. - * You may avoid server disconnections while the client is idle by - * periodicaly sending NOOP commands to the server. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- * Listing API Examples - * Both paged and unpaged examples of directory listings are available, - * as follows: - *

- * Unpaged (whole list) access, using a parser accessible by auto-detect: - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * Paged access, using a parser not accessible by auto-detect. The class - * defined in the first parameter of initateListParsing should be derived - * from org.apache.commons.net.FTPFileEntryParser: - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine =
- *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * Paged access, using a parser accessible by auto-detect: - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine = f.initiateListParsing(directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * For examples of using FTPClient on servers whose directory listings - *

    - *
  • use languages other than English
  • - *
  • use date formats other than the American English "standard" MM d yyyy
  • - *
  • are in different timezones and you need accurate timestamps for dependency checking - * as in Ant
  • - *
see {@link FTPClientConfig FTPClientConfig}. - *

- * @author Daniel F. Savarese - * @author Rory Winston - * @see FTP - * @see FTPConnectionClosedException - * @see FTPFileEntryParser - * @see FTPFileEntryParserFactory - * @see DefaultFTPFileEntryParserFactory - * @see FTPClientConfig - * - * @see org.apache.commons.net.MalformedServerReplyException - **/ -public class FTPClient extends FTP -implements Configurable -{ - /*** - * A constant indicating the FTP session is expecting all transfers - * to occur between the client (local) and server and that the server - * should connect to the client's data port to initiate a data transfer. - * This is the default data connection mode when and FTPClient instance - * is created. - ***/ - public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0; - /*** - * A constant indicating the FTP session is expecting all transfers - * to occur between two remote servers and that the server - * the client is connected to should connect to the other server's - * data port to initiate a data transfer. - ***/ - public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1; - /*** - * A constant indicating the FTP session is expecting all transfers - * to occur between the client (local) and server and that the server - * is in passive mode, requiring the client to connect to the - * server's data port to initiate a transfer. - ***/ - public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2; - /*** - * A constant indicating the FTP session is expecting all transfers - * to occur between two remote servers and that the server - * the client is connected to is in passive mode, requiring the other - * server to connect to the first server's data port to initiate a data - * transfer. - ***/ - public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3; - - private int __dataConnectionMode, __dataTimeout; - private int __passivePort; - private String __passiveHost; - private int __fileType, __fileFormat, __fileStructure, __fileTransferMode; - private boolean __remoteVerificationEnabled; - private long __restartOffset; - private FTPFileEntryParserFactory __parserFactory; - private int __bufferSize; - private boolean __listHiddenFiles; - - // __systemName is a cached value that should not be referenced directly - // except when assigned in getSystemName and __initDefaults. - private String __systemName; - - // __entryParser is a cached value that should not be referenced directly - // except when assigned in listFiles(String, String) and __initDefaults. - private FTPFileEntryParser __entryParser; - - private FTPClientConfig __configuration; - - /** Pattern for PASV mode responses */ - private static String __parms = "\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}"; - private static java.util.regex.Pattern __parms_pat; - static { - __parms_pat = java.util.regex.Pattern.compile(__parms); - } - - /*** - * Default FTPClient constructor. Creates a new FTPClient instance - * with the data connection mode set to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE , the file type - * set to FTP.ASCII_FILE_TYPE , the - * file format set to FTP.NON_PRINT_TEXT_FORMAT , - * the file structure set to FTP.FILE_STRUCTURE , and - * the transfer mode set to FTP.STREAM_TRANSFER_MODE . - ***/ - public FTPClient() - { - __initDefaults(); - __dataTimeout = -1; - __remoteVerificationEnabled = true; - __parserFactory = new DefaultFTPFileEntryParserFactory(); - __configuration = null; - __listHiddenFiles = false; - } - - - private void __initDefaults() - { - __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; - __passiveHost = null; - __passivePort = -1; - __fileType = FTP.ASCII_FILE_TYPE; - __fileStructure = FTP.FILE_STRUCTURE; - __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; - __fileTransferMode = FTP.STREAM_TRANSFER_MODE; - __restartOffset = 0; - __systemName = null; - __entryParser = null; - __bufferSize = Util.DEFAULT_COPY_BUFFER_SIZE; - } - - private String __parsePathname(String reply) - { - int begin, end; - - begin = reply.indexOf('"') + 1; - end = reply.indexOf('"', begin); - - return reply.substring(begin, end); - } - - - private void __parsePassiveModeReply(String reply) - throws MalformedServerReplyException - { - java.util.regex.Matcher m = __parms_pat.matcher(reply); - if (!m.find()) { - throw new MalformedServerReplyException( - "Could not parse passive host information.\nServer Reply: " + reply); - } - reply = m.group(); - String parts[] = m.group().split(","); - - __passiveHost = parts[0] + '.' + parts[1] + '.' + parts[2] + '.' + parts[3]; - - try - { - int oct1 = Integer.parseInt(parts[4]); - int oct2 = Integer.parseInt(parts[5]); - __passivePort = (oct1 << 8) | oct2; - } - catch (NumberFormatException e) - { - throw new MalformedServerReplyException( - "Could not parse passive host information.\nServer Reply: " + reply); - } - - } - - private boolean __storeFile(int command, String remote, InputStream local) - throws IOException - { - OutputStream output; - Socket socket; - - if ((socket = _openDataConnection_(command, remote)) == null) - return false; - - output = new BufferedOutputStream(socket.getOutputStream(), - getBufferSize() - ); - if (__fileType == ASCII_FILE_TYPE) - output = new ToNetASCIIOutputStream(output); - // Treat everything else as binary for now - try - { - Util.copyStream(local, output, getBufferSize(), - CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, - false); - } - catch (IOException e) - { - try - { - socket.close(); - } - catch (IOException f) - {} - throw e; - } - output.close(); - socket.close(); - return completePendingCommand(); - } - - private OutputStream __storeFileStream(int command, String remote) - throws IOException - { - OutputStream output; - Socket socket; - - if ((socket = _openDataConnection_(command, remote)) == null) - return null; - - output = socket.getOutputStream(); - if (__fileType == ASCII_FILE_TYPE) { - // We buffer ascii transfers because the buffering has to - // be interposed between ToNetASCIIOutputSream and the underlying - // socket output stream. We don't buffer binary transfers - // because we don't want to impose a buffering policy on the - // programmer if possible. Programmers can decide on their - // own if they want to wrap the SocketOutputStream we return - // for file types other than ASCII. - output = new BufferedOutputStream(output, - getBufferSize()); - output = new ToNetASCIIOutputStream(output); - - } - return new org.apache.commons.net.io.SocketOutputStream(socket, output); - } - - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - *

- * @param command The text representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - protected Socket _openDataConnection_(int command, String arg) - throws IOException - { - Socket socket; - - if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE && - __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) - return null; - - if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) - { - ServerSocket server; - server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); - - if (!FTPReply.isPositiveCompletion(port(getLocalAddress(), - server.getLocalPort()))) - { - server.close(); - return null; - } - - if ((__restartOffset > 0) && !restart(__restartOffset)) - { - server.close(); - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) - { - server.close(); - return null; - } - - // For now, let's just use the data timeout value for waiting for - // the data connection. It may be desirable to let this be a - // separately configurable value. In any case, we really want - // to allow preventing the accept from blocking indefinitely. - if (__dataTimeout >= 0) - server.setSoTimeout(__dataTimeout); - try { - socket = server.accept(); - } finally { - server.close(); - } - } - else - { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE - - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) - return null; - - __parsePassiveModeReply(_replyLines.get(_replyLines.size() - 1)); - - socket = _socketFactory_.createSocket(__passiveHost, __passivePort); - if ((__restartOffset > 0) && !restart(__restartOffset)) - { - socket.close(); - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) - { - socket.close(); - return null; - } - } - - if (__remoteVerificationEnabled && !verifyRemote(socket)) - { - InetAddress host1, host2; - - host1 = socket.getInetAddress(); - host2 = getRemoteAddress(); - - socket.close(); - - throw new IOException( - "Host attempting data connection " + host1.getHostAddress() + - " is not same as server " + host2.getHostAddress()); - } - - if (__dataTimeout >= 0) - socket.setSoTimeout(__dataTimeout); - - return socket; - } - - - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - __initDefaults(); - } - - - /*** - * Sets the timeout in milliseconds to use when reading from the - * data connection. This timeout will be set immediately after - * opening the data connection. - *

- * @param timeout The default timeout in milliseconds that is used when - * opening a data connection socket. - ***/ - public void setDataTimeout(int timeout) - { - __dataTimeout = timeout; - } - - /** - * set the factory used for parser creation to the supplied factory object. - * - * @param parserFactory - * factory object used to create FTPFileEntryParsers - * - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - */ - public void setParserFactory(FTPFileEntryParserFactory parserFactory) { - __parserFactory = parserFactory; - } - - - /*** - * Closes the connection to the FTP server and restores - * connection parameters to the default values. - *

- * @exception IOException If an error occurs while disconnecting. - ***/ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - __initDefaults(); - } - - - /*** - * Enable or disable verification that the remote host taking part - * of a data connection is the same as the host to which the control - * connection is attached. The default is for verification to be - * enabled. You may set this value at any time, whether the - * FTPClient is currently connected or not. - *

- * @param enable True to enable verification, false to disable verification. - ***/ - public void setRemoteVerificationEnabled(boolean enable) - { - __remoteVerificationEnabled = enable; - } - - /*** - * Return whether or not verification of the remote host participating - * in data connections is enabled. The default behavior is for - * verification to be enabled. - *

- * @return True if verification is enabled, false if not. - ***/ - public boolean isRemoteVerificationEnabled() - { - return __remoteVerificationEnabled; - } - - /*** - * Login to the FTP server using the provided username and password. - *

- * @param username The username to login under. - * @param password The password to use. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean login(String username, String password) throws IOException - { - user(username); - - if (FTPReply.isPositiveCompletion(_replyCode)) - return true; - - // If we get here, we either have an error code, or an intermmediate - // reply requesting password. - if (!FTPReply.isPositiveIntermediate(_replyCode)) - return false; - - return FTPReply.isPositiveCompletion(pass(password)); - } - - - /*** - * Login to the FTP server using the provided username, password, - * and account. If no account is required by the server, only - * the username and password, the account information is not used. - *

- * @param username The username to login under. - * @param password The password to use. - * @param account The account to use. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean login(String username, String password, String account) - throws IOException - { - user(username); - - if (FTPReply.isPositiveCompletion(_replyCode)) - return true; - - // If we get here, we either have an error code, or an intermmediate - // reply requesting password. - if (!FTPReply.isPositiveIntermediate(_replyCode)) - return false; - - pass(password); - - if (FTPReply.isPositiveCompletion(_replyCode)) - return true; - - if (!FTPReply.isPositiveIntermediate(_replyCode)) - return false; - - return FTPReply.isPositiveCompletion(acct(account)); - } - - /*** - * Logout of the FTP server by sending the QUIT command. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean logout() throws IOException - { - return FTPReply.isPositiveCompletion(quit()); - } - - - /*** - * Change the current working directory of the FTP session. - *

- * @param pathname The new current working directory. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean changeWorkingDirectory(String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(cwd(pathname)); - } - - - /*** - * Change to the parent directory of the current working directory. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean changeToParentDirectory() throws IOException - { - return FTPReply.isPositiveCompletion(cdup()); - } - - - /*** - * Issue the FTP SMNT command. - *

- * @param pathname The pathname to mount. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean structureMount(String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(smnt(pathname)); - } - - /*** - * Reinitialize the FTP session. Not all FTP servers support this - * command, which issues the FTP REIN command. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - boolean reinitialize() throws IOException - { - rein(); - - if (FTPReply.isPositiveCompletion(_replyCode) || - (FTPReply.isPositivePreliminary(_replyCode) && - FTPReply.isPositiveCompletion(getReply()))) - { - - __initDefaults(); - - return true; - } - - return false; - } - - - /*** - * Set the current data connection mode to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE. No communication - * with the FTP server is conducted, but this causes all future data - * transfers to require the FTP server to connect to the client's - * data port. Additionally, to accommodate differences between socket - * implementations on different platforms, this method causes the - * client to issue a PORT command before every data transfer. - ***/ - public void enterLocalActiveMode() - { - __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; - __passiveHost = null; - __passivePort = -1; - } - - - /*** - * Set the current data connection mode to - * PASSIVE_LOCAL_DATA_CONNECTION_MODE . Use this - * method only for data transfers between the client and server. - * This method causes a PASV command to be issued to the server - * before the opening of every data connection, telling the server to - * open a data port to which the client will connect to conduct - * data transfers. The FTPClient will stay in - * PASSIVE_LOCAL_DATA_CONNECTION_MODE until the - * mode is changed by calling some other method such as - * {@link #enterLocalActiveMode enterLocalActiveMode() } - ***/ - public void enterLocalPassiveMode() - { - __dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE; - // These will be set when just before a data connection is opened - // in _openDataConnection_() - __passiveHost = null; - __passivePort = -1; - } - - - /*** - * Set the current data connection mode to - * ACTIVE_REMOTE_DATA_CONNECTION . Use this method only - * for server to server data transfers. This method issues a PORT - * command to the server, indicating the other server and port to which - * it should connect for data transfers. You must call this method - * before EVERY server to server transfer attempt. The FTPClient will - * NOT automatically continue to issue PORT commands. You also - * must remember to call - * {@link #enterLocalActiveMode enterLocalActiveMode() } if you - * wish to return to the normal data connection mode. - *

- * @param host The passive mode server accepting connections for data - * transfers. - * @param port The passive mode server's data port. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean enterRemoteActiveMode(InetAddress host, int port) - throws IOException - { - if (FTPReply.isPositiveCompletion(port(host, port))) - { - __dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE; - __passiveHost = null; - __passivePort = -1; - return true; - } - return false; - } - - /*** - * Set the current data connection mode to - * PASSIVE_REMOTE_DATA_CONNECTION_MODE . Use this - * method only for server to server data transfers. - * This method issues a PASV command to the server, telling it to - * open a data port to which the active server will connect to conduct - * data transfers. You must call this method - * before EVERY server to server transfer attempt. The FTPClient will - * NOT automatically continue to issue PASV commands. You also - * must remember to call - * {@link #enterLocalActiveMode enterLocalActiveMode() } if you - * wish to return to the normal data connection mode. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean enterRemotePassiveMode() throws IOException - { - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) - return false; - - __dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE; - __parsePassiveModeReply(_replyLines.get(0)); - - return true; - } - - /*** - * Returns the hostname or IP address (in the form of a string) returned - * by the server when entering passive mode. If not in passive mode, - * returns null. This method only returns a valid value AFTER a - * data connection has been opened after a call to - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * This is because FTPClient sends a PASV command to the server only - * just before opening a data connection, and not when you call - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - *

- * @return The passive host name if in passive mode, otherwise null. - ***/ - public String getPassiveHost() - { - return __passiveHost; - } - - /*** - * If in passive mode, returns the data port of the passive host. - * This method only returns a valid value AFTER a - * data connection has been opened after a call to - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * This is because FTPClient sends a PASV command to the server only - * just before opening a data connection, and not when you call - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - *

- * @return The data port of the passive server. If not in passive - * mode, undefined. - ***/ - public int getPassivePort() - { - return __passivePort; - } - - - /*** - * Returns the current data connection mode (one of the - * _DATA_CONNECTION_MODE constants. - *

- * @return The current data connection mode (one of the - * _DATA_CONNECTION_MODE constants. - ***/ - public int getDataConnectionMode() - { - return __dataConnectionMode; - } - - - /*** - * Sets the file type to be transferred. This should be one of - * FTP.ASCII_FILE_TYPE , FTP.BINARY_FILE_TYPE, - * etc. The file type only needs to be set when you want to change the - * type. After changing it, the new type stays in effect until you change - * it again. The default file type is FTP.ASCII_FILE_TYPE - * if this method is never called. - *

- * @param fileType The _FILE_TYPE constant indcating the - * type of file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean setFileType(int fileType) throws IOException - { - if (FTPReply.isPositiveCompletion(type(fileType))) - { - __fileType = fileType; - __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; - return true; - } - return false; - } - - - /*** - * Sets the file type to be transferred and the format. The type should be - * one of FTP.ASCII_FILE_TYPE , - * FTP.BINARY_FILE_TYPE , etc. The file type only needs to - * be set when you want to change the type. After changing it, the new - * type stays in effect until you change it again. The default file type - * is FTP.ASCII_FILE_TYPE if this method is never called. - * The format should be one of the FTP class TEXT_FORMAT - * constants, or if the type is FTP.LOCAL_FILE_TYPE , the - * format should be the byte size for that type. The default format - * is FTP.NON_PRINT_TEXT_FORMAT if this method is never - * called. - *

- * @param fileType The _FILE_TYPE constant indcating the - * type of file. - * @param formatOrByteSize The format of the file (one of the - * _FORMAT constants. In the case of - * LOCAL_FILE_TYPE, the byte size. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean setFileType(int fileType, int formatOrByteSize) - throws IOException - { - if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) - { - __fileType = fileType; - __fileFormat = formatOrByteSize; - return true; - } - return false; - } - - - /*** - * Sets the file structure. The default structure is - * FTP.FILE_STRUCTURE if this method is never called. - *

- * @param structure The structure of the file (one of the FTP class - * _STRUCTURE constants). - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean setFileStructure(int structure) throws IOException - { - if (FTPReply.isPositiveCompletion(stru(structure))) - { - __fileStructure = structure; - return true; - } - return false; - } - - - /*** - * Sets the transfer mode. The default transfer mode - * FTP.STREAM_TRANSFER_MODE if this method is never called. - *

- * @param mode The new transfer mode to use (one of the FTP class - * _TRANSFER_MODE constants). - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean setFileTransferMode(int mode) throws IOException - { - if (FTPReply.isPositiveCompletion(mode(mode))) - { - __fileTransferMode = mode; - return true; - } - return false; - } - - - /*** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to retrieve a given file from - * the other server. - *

- * @param filename The name of the file to retrieve. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean remoteRetrieve(String filename) throws IOException - { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) - return FTPReply.isPositivePreliminary(retr(filename)); - return false; - } - - - /*** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using the given filename. The other server must - * have had a remoteRetrieve issued to it by another - * FTPClient. - *

- * @param filename The name to call the file that is to be stored. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean remoteStore(String filename) throws IOException - { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) - return FTPReply.isPositivePreliminary(stor(filename)); - return false; - } - - - /*** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using a unique filename based on the given filename. - * The other server must have had a remoteRetrieve issued - * to it by another FTPClient. - *

- * @param filename The name on which to base the filename of the file - * that is to be stored. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean remoteStoreUnique(String filename) throws IOException - { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) - return FTPReply.isPositivePreliminary(stou(filename)); - return false; - } - - - /*** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using a unique filename. - * The other server must have had a remoteRetrieve issued - * to it by another FTPClient. Many FTP servers require that a base - * filename be given from which the unique filename can be derived. For - * those servers use the other version of remoteStoreUnique - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean remoteStoreUnique() throws IOException - { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) - return FTPReply.isPositivePreliminary(stou()); - return false; - } - - // For server to server transfers - /*** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to append to a given file on - * the other server. The other server must have had a - * remoteRetrieve issued to it by another FTPClient. - *

- * @param filename The name of the file to be appended to, or if the - * file does not exist, the name to call the file being stored. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean remoteAppend(String filename) throws IOException - { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) - return FTPReply.isPositivePreliminary(stor(filename)); - return false; - } - - /*** - * There are a few FTPClient methods that do not complete the - * entire sequence of FTP commands to complete a transaction. These - * commands require some action by the programmer after the reception - * of a positive intermediate command. After the programmer's code - * completes its actions, it must call this method to receive - * the completion reply from the server and verify the success of the - * entire transaction. - *

- * For example, - *

-     * InputStream input;
-     * OutputStream output;
-     * input  = new FileInputStream("foobaz.txt");
-     * output = ftp.storeFileStream("foobar.txt")
-     * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
-     *     input.close();
-     *     output.close();
-     *     ftp.logout();
-     *     ftp.disconnect();
-     *     System.err.println("File transfer failed.");
-     *     System.exit(1);
-     * }
-     * Util.copyStream(input, output);
-     * input.close();
-     * output.close();
-     * // Must call completePendingCommand() to finish command.
-     * if(!ftp.completePendingCommand()) {
-     *     ftp.logout();
-     *     ftp.disconnect();
-     *     System.err.println("File transfer failed.");
-     *     System.exit(1);
-     * }
-     * 
- *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean completePendingCommand() throws IOException - { - return FTPReply.isPositiveCompletion(getReply()); - } - - - /*** - * Retrieves a named file from the server and writes it to the given - * OutputStream. This method does NOT close the given OutputStream. - * If the current file type is ASCII, line separators in the file are - * converted to the local representation. - *

- * @param remote The name of the remote file. - * @param local The local OutputStream to which to write the file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean retrieveFile(String remote, OutputStream local) - throws IOException - { - InputStream input; - Socket socket; - - if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) - return false; - - input = new BufferedInputStream(socket.getInputStream(), - getBufferSize()); - if (__fileType == ASCII_FILE_TYPE) - input = new FromNetASCIIInputStream(input); - // Treat everything else as binary for now - try - { - Util.copyStream(input, local, getBufferSize(), - CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, - false); - } - catch (IOException e) - { - try - { - socket.close(); - } - catch (IOException f) - {} - throw e; - } - socket.close(); - return completePendingCommand(); - } - - /*** - * Returns an InputStream from which a named file from the server - * can be read. If the current file type is ASCII, the returned - * InputStream will convert line separators in the file to - * the local representation. You must close the InputStream when you - * finish reading from it. The InputStream itself will take care of - * closing the parent data connection socket upon being closed. To - * finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - *

- * @param remote The name of the remote file. - * @return An InputStream from which the remote file can be read. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public InputStream retrieveFileStream(String remote) throws IOException - { - InputStream input; - Socket socket; - - if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null) - return null; - - input = socket.getInputStream(); - if (__fileType == ASCII_FILE_TYPE) { - // We buffer ascii transfers because the buffering has to - // be interposed between FromNetASCIIOutputSream and the underlying - // socket input stream. We don't buffer binary transfers - // because we don't want to impose a buffering policy on the - // programmer if possible. Programmers can decide on their - // own if they want to wrap the SocketInputStream we return - // for file types other than ASCII. - input = new BufferedInputStream(input, - getBufferSize()); - input = new FromNetASCIIInputStream(input); - } - return new org.apache.commons.net.io.SocketInputStream(socket, input); - } - - - /*** - * Stores a file on the server using the given name and taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - *

- * @param remote The name to give the remote file. - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean storeFile(String remote, InputStream local) - throws IOException - { - return __storeFile(FTPCommand.STOR, remote, local); - } - - - /*** - * Returns an OutputStream through which data can be written to store - * a file on the server using the given name. If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - *

- * @param remote The name to give the remote file. - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public OutputStream storeFileStream(String remote) throws IOException - { - return __storeFileStream(FTPCommand.STOR, remote); - } - - /*** - * Appends to a file on the server with the given name, taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - *

- * @param remote The name of the remote file. - * @param local The local InputStream from which to read the data to - * be appended to the remote file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean appendFile(String remote, InputStream local) - throws IOException - { - return __storeFile(FTPCommand.APPE, remote, local); - } - - /*** - * Returns an OutputStream through which data can be written to append - * to a file on the server with the given name. If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - *

- * @param remote The name of the remote file. - * @return An OutputStream through which the remote file can be appended. - * If the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public OutputStream appendFileStream(String remote) throws IOException - { - return __storeFileStream(FTPCommand.APPE, remote); - } - - /*** - * Stores a file on the server using a unique name derived from the - * given name and taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - *

- * @param remote The name on which to base the unique name given to - * the remote file. - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean storeUniqueFile(String remote, InputStream local) - throws IOException - { - return __storeFile(FTPCommand.STOU, remote, local); - } - - - /*** - * Returns an OutputStream through which data can be written to store - * a file on the server using a unique name derived from the given name. - * If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - *

- * @param remote The name on which to base the unique name given to - * the remote file. - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public OutputStream storeUniqueFileStream(String remote) throws IOException - { - return __storeFileStream(FTPCommand.STOU, remote); - } - - /** - * Stores a file on the server using a unique name assigned by the - * server and taking input from the given InputStream. This method does - * NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - *

- * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeUniqueFile(InputStream local) throws IOException - { - return __storeFile(FTPCommand.STOU, null, local); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using a unique name assigned by the server. - * If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - *

- * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeUniqueFileStream() throws IOException - { - return __storeFileStream(FTPCommand.STOU, null); - } - - /*** - * Reserve a number of bytes on the server for the next file transfer. - *

- * @param bytes The number of bytes which the server should allocate. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean allocate(int bytes) throws IOException - { - return FTPReply.isPositiveCompletion(allo(bytes)); - } - - - /** - * Reserve space on the server for the next file transfer. - *

- * @param bytes The number of bytes which the server should allocate. - * @param recordSize The size of a file record. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(int bytes, int recordSize) throws IOException - { - return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); - } - - - /*** - * Restart a STREAM_TRANSFER_MODE file transfer starting - * from the given offset. This will only work on FTP servers supporting - * the REST comand for the stream transfer mode. However, most FTP - * servers support this. Any subsequent file transfer will start - * reading or writing the remote file from the indicated offset. - *

- * @param offset The offset into the remote file at which to start the - * next file transfer. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - private boolean restart(long offset) throws IOException - { - __restartOffset = 0; - return FTPReply.isPositiveIntermediate(rest(Long.toString(offset))); - } - - /*** - * Sets the restart offset. The restart command is sent to the server - * only before sending the file transfer command. When this is done, - * the restart marker is reset to zero. - *

- * @param offset The offset into the remote file at which to start the - * next file transfer. This must be a value greater than or - * equal to zero. - ***/ - public void setRestartOffset(long offset) - { - if (offset >= 0) - __restartOffset = offset; - } - - /*** - * Fetches the restart offset. - *

- * @return offset The offset into the remote file at which to start the - * next file transfer. - ***/ - public long getRestartOffset() - { - return __restartOffset; - } - - - - /*** - * Renames a remote file. - *

- * @param from The name of the remote file to rename. - * @param to The new name of the remote file. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean rename(String from, String to) throws IOException - { - if (!FTPReply.isPositiveIntermediate(rnfr(from))) - return false; - - return FTPReply.isPositiveCompletion(rnto(to)); - } - - - /*** - * Abort a transfer in progress. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean abort() throws IOException - { - return FTPReply.isPositiveCompletion(abor()); - } - - /*** - * Deletes a file on the FTP server. - *

- * @param pathname The pathname of the file to be deleted. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean deleteFile(String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(dele(pathname)); - } - - - /*** - * Removes a directory on the FTP server (if empty). - *

- * @param pathname The pathname of the directory to remove. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean removeDirectory(String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(rmd(pathname)); - } - - - /*** - * Creates a new subdirectory on the FTP server in the current directory - * (if a relative pathname is given) or where specified (if an absolute - * pathname is given). - *

- * @param pathname The pathname of the directory to create. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean makeDirectory(String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(mkd(pathname)); - } - - - /*** - * Returns the pathname of the current working directory. - *

- * @return The pathname of the current working directory. If it cannot - * be obtained, returns null. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String printWorkingDirectory() throws IOException - { - if (pwd() != FTPReply.PATHNAME_CREATED) - return null; - - return __parsePathname(_replyLines.get( _replyLines.size() - 1)); - } - - - /** - * Send a site specific command. - * @param arguments The site specific command and arguments. - * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendSiteCommand(String arguments) throws IOException - { - return FTPReply.isPositiveCompletion(site(arguments)); - } - - - /*** - * Fetches the system type name from the server and returns the string. - * This value is cached for the duration of the connection after the - * first call to this method. In other words, only the first time - * that you invoke this method will it issue a SYST command to the - * FTP server. FTPClient will remember the value and return the - * cached value until a call to disconnect. - *

- * @return The system type name obtained from the server. null if the - * information could not be obtained. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String getSystemName() throws IOException - { - //if (syst() == FTPReply.NAME_SYSTEM_TYPE) - // Technically, we should expect a NAME_SYSTEM_TYPE response, but - // in practice FTP servers deviate, so we soften the condition to - // a positive completion. - if (__systemName == null && FTPReply.isPositiveCompletion(syst())) - __systemName = _replyLines.get(_replyLines.size() - 1).substring(4); - - return __systemName; - } - - - /*** - * Fetches the system help information from the server and returns the - * full string. - *

- * @return The system help string obtained from the server. null if the - * information could not be obtained. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String listHelp() throws IOException - { - if (FTPReply.isPositiveCompletion(help())) - return getReplyString(); - return null; - } - - - /** - * Fetches the help information for a given command from the server and - * returns the full string. - * @param command The command on which to ask for help. - * @return The command help string obtained from the server. null if the - * information could not be obtained. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp(String command) throws IOException - { - if (FTPReply.isPositiveCompletion(help(command))) - return getReplyString(); - return null; - } - - - /*** - * Sends a NOOP command to the FTP server. This is useful for preventing - * server timeouts. - *

- * @return True if successfully completed, false if not. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean sendNoOp() throws IOException - { - return FTPReply.isPositiveCompletion(noop()); - } - - - /*** - * Obtain a list of filenames in a directory (or just the name of a given - * file, which is not particularly useful). This information is obtained - * through the NLST command. If the given pathname is a directory and - * contains no files, a zero length array is returned only - * if the FTP server returned a positive completion code, otherwise - * null is returned (the FTP server returned a 550 error No files found.). - * If the directory is not empty, an array of filenames in the directory is - * returned. If the pathname corresponds - * to a file, only that file will be listed. The server may or may not - * expand glob expressions. - *

- * @param pathname The file or directory to list. - * @return The list of filenames contained in the given path. null if - * the list could not be obtained. If there are no filenames in - * the directory, a zero-length array is returned. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String[] listNames(String pathname) throws IOException - { - String line; - Socket socket; - BufferedReader reader; - ArrayList results; - - if ((socket = _openDataConnection_(FTPCommand.NLST, pathname)) == null) - return null; - - reader = - new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); - - results = new ArrayList(); - while ((line = reader.readLine()) != null) - results.add(line); - - reader.close(); - socket.close(); - - if (completePendingCommand()) - { - String[] names = new String[ results.size() ]; - return results.toArray(names); - } - - return null; - } - - - /*** - * Obtain a list of filenames in the current working directory - * This information is obtained through the NLST command. If the current - * directory contains no files, a zero length array is returned only - * if the FTP server returned a positive completion code, otherwise, - * null is returned (the FTP server returned a 550 error No files found.). - * If the directory is not empty, an array of filenames in the directory is - * returned. - *

- * @return The list of filenames contained in the current working - * directory. null if the list could not be obtained. - * If there are no filenames in the directory, a zero-length array - * is returned. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String[] listNames() throws IOException - { - return listNames(null); - } - - - - /** - * Using the default system autodetect mechanism, obtain a - * list of file information for the current working directory - * or for just a single file. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * @param pathname The file or directory to list. Since the server may - * or may not expand glob expressions, using them here - * is not recommended and may well cause this method to - * fail. - * - * @return The list of file information contained in the given path in - * the format determined by the autodetection mechanism - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @exception IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @exception ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.FTPFileEntryParser - */ - public FTPFile[] listFiles(String pathname) - throws IOException - { - String key = null; - FTPListParseEngine engine = - initiateListParsing(key, pathname); - return engine.getFiles(); - - } - /** - * Using the default system autodetect mechanism, obtain a - * list of file information for the current working directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * @return The list of file information contained in the current directory - * in the format determined by the autodetection mechanism. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @exception IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @exception ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.FTPFileEntryParser - */ - public FTPFile[] listFiles() - throws IOException - { - return listFiles((String) null); - } - - /** - * Using the default autodetect mechanism, initialize an FTPListParseEngine - * object containing a raw file information for the current working - * directory on the server - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @exception ParserInitializationException - * Thrown if the autodetect mechanism cannot - * resolve the type of system we are connected with. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing() - throws IOException - { - return initiateListParsing((String) null); - } - - /** - * Using the default autodetect mechanism, initialize an FTPListParseEngine - * object containing a raw file information for the supplied directory. - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * The server may or may not expand glob expressions. You should avoid - * using glob expressions because the return format for glob listings - * differs from server to server and will likely cause this method to fail. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - *

- *

-     *    FTPClient f=FTPClient();
-     *    f.connect(server);
-     *    f.login(username, password);
-     *    FTPListParseEngine engine = f.initiateListParsing(directory);
-     *
-     *    while (engine.hasNext()) {
-     *       FTPFile[] files = engine.getNext(25);  // "page size" you want
-     *       //do whatever you want with these files, display them, etc.
-     *       //expensive FTPFile objects not created until needed.
-     *    }
-     * 
- * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @exception ParserInitializationException - * Thrown if the autodetect mechanism cannot - * resolve the type of system we are connected with. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing( - String pathname) - throws IOException - { - String key = null; - return initiateListParsing(key, pathname); - } - - /** - * Using the supplied parser key, initialize an FTPListParseEngine - * object containing a raw file information for the supplied directory. - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * The server may or may not expand glob expressions. You should avoid - * using glob expressions because the return format for glob listings - * differs from server to server and will likely cause this method to fail. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - * @param parserKey A string representing a designated code or fully-qualified - * class name of an FTPFileEntryParser that should be - * used to parse each server file listing. - * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @exception ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing( - String parserKey, String pathname) - throws IOException - { - // We cache the value to avoid creation of a new object every - // time a file listing is generated. - if(__entryParser == null) { - if (null != parserKey) { - // if a parser key was supplied in the parameters, - // use that to create the paraser - __entryParser = - __parserFactory.createFileEntryParser(parserKey); - - } else { - // if no parserKey was supplied, check for a configuration - // in the params, and if non-null, use that. - if (null != __configuration) { - __entryParser = - __parserFactory.createFileEntryParser(__configuration); - } else { - // if a parserKey hasn't been supplied, and a configuration - // hasn't been supplied, then autodetect by calling - // the SYST command and use that to choose the parser. - __entryParser = - __parserFactory.createFileEntryParser(getSystemName()); - } - } - } - - return initiateListParsing(__entryParser, pathname); - - } - - - /** - * private method through which all listFiles() and - * initiateListParsing methods pass once a parser is determined. - * - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @see FTPListParseEngine - */ - private FTPListParseEngine initiateListParsing( - FTPFileEntryParser parser, String pathname) - throws IOException - { - Socket socket; - - FTPListParseEngine engine = new FTPListParseEngine(parser); - - if ((socket = _openDataConnection_(FTPCommand.LIST, getListArguments(pathname))) == null) - { - return engine; - } - - - try { - engine.readServerList(socket.getInputStream(), getControlEncoding()); - } - finally { - socket.close(); - } - - completePendingCommand(); - return engine; - } - - /** - * @since 2.0 - */ - protected String getListArguments(String pathname) { - if (getListHiddenFiles()) - { - StringBuffer sb = new StringBuffer(pathname.length() + 3); - sb.append("-a "); - sb.append(pathname); - return sb.toString(); - } - - return pathname; - } - - - /*** - * Issue the FTP STAT command to the server. - *

- * @return The status information returned by the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String getStatus() throws IOException - { - if (FTPReply.isPositiveCompletion(stat())) - return getReplyString(); - return null; - } - - - /*** - * Issue the FTP STAT command to the server for a given pathname. This - * should produce a listing of the file or directory. - *

- * @return The status information returned by the server. - * @exception FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String getStatus(String pathname) throws IOException - { - if (FTPReply.isPositiveCompletion(stat(pathname))) - return getReplyString(); - return null; - } - - - /** - * Issue the FTP MDTM command (not supported by all servers to retrieve the last - * modification time of a file. The modification string should be in the - * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in - * GMT, but not all FTP servers honour this. - * - * @param pathname The file path to query. - * @return A string representing the last file modification time in YYYYMMDDhhmmss format. - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - public String getModificationTime(String pathname) throws IOException { - if (FTPReply.isPositiveCompletion(mdtm(pathname))) - return getReplyString(); - return null; - } - - - /** - * Set the internal buffer size. - * - * @param bufSize The size of the buffer - */ - public void setBufferSize(int bufSize) { - __bufferSize = bufSize; - } - - /** - * Retrieve the current internal buffer size. - * @return The current buffer size. - */ - public int getBufferSize() { - return __bufferSize; - } - - - /** - * Implementation of the {@link Configurable Configurable} interface. - * In the case of this class, configuring merely makes the config object available for the - * factory methods that construct parsers. - * @param config {@link FTPClientConfig FTPClientConfig} object used to - * provide non-standard configurations to the parser. - * @since 1.4 - */ - public void configure(FTPClientConfig config) { - this.__configuration = config; - } - - /** - * You can set this to true if you would like to get hidden files when {@link #listFiles} too. - * A LIST -a will be issued to the ftp server. - * It depends on your ftp server if you need to call this method, also dont expect to get rid - * of hidden files if you call this method with "false". - * - * @param listHiddenFiles true if hidden files should be listed - * @since 2.0 - */ - public void setListHiddenFiles(boolean listHiddenFiles) { - this.__listHiddenFiles = listHiddenFiles; - } - - /** - * @see #setListHiddenFiles(boolean) - * @return the current state - * @since 2.0 - */ - public boolean getListHiddenFiles() { - return this.__listHiddenFiles; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/ftp/FTPClientConfig.class b/org/apache/commons/net/ftp/FTPClientConfig.class deleted file mode 100644 index b42c8ee..0000000 Binary files a/org/apache/commons/net/ftp/FTPClientConfig.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPClientConfig.java b/org/apache/commons/net/ftp/FTPClientConfig.java deleted file mode 100644 index 450eddc..0000000 --- a/org/apache/commons/net/ftp/FTPClientConfig.java +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.text.DateFormatSymbols; -import java.util.Collection; -import java.util.Locale; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TreeMap; - -/** - *

- * This class implements an alternate means of configuring the - * {@link org.apache.commons.net.ftp.FTPClient FTPClient} object and - * also subordinate objects which it uses. Any class implementing the - * {@link org.apache.commons.net.ftp.Configurable Configurable } - * interface can be configured by this object. - *

- * In particular this class was designed primarily to support configuration - * of FTP servers which express file timestamps in formats and languages - * other than those for the US locale, which although it is the most common - * is not universal. Unfortunately, nothing in the FTP spec allows this to - * be determined in an automated way, so manual configuration such as this - * is necessary. - *

- * This functionality was designed to allow existing clients to work exactly - * as before without requiring use of this component. This component should - * only need to be explicitly invoked by the user of this package for problem - * cases that previous implementations could not solve. - *

- *

Examples of use of FTPClientConfig

- * Use cases: - * You are trying to access a server that - *
    - *
  • lists files with timestamps that use month names in languages other - * than English
  • - *
  • lists files with timestamps that use date formats other - * than the American English "standard" MM dd yyyy
  • - *
  • is in different timezone and you need accurate timestamps for - * dependency checking as in Ant
  • - *
- *

- * Unpaged (whole list) access on a UNIX server that uses French month names - * but uses the "standard" MMM d yyyy date formatting - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setServerLanguageCode("fr");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- *

- * Paged access on a UNIX server that uses Danish month names - * and "European" date formatting in Denmark's time zone, when you - * are in some other time zone. - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setServerLanguageCode("da");
- *    conf.setDefaultDateFormat("d MMM yyyy");
- *    conf.setRecentDateFormat("d MMM HH:mm");
- *    conf.setTimeZoneId("Europe/Copenhagen");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine =
- *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- *

- * Unpaged (whole list) access on a VMS server that uses month names - * in a language not {@link #getSupportedLanguageCodes() supported} by the system. - * but uses the "standard" MMM d yyyy date formatting - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS);
- *    conf.setShortMonthNames(
- *        "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- *

- * Unpaged (whole list) access on a Windows-NT server in a different time zone. - * (Note, since the NT Format uses numeric date formatting, language issues - * are irrelevant here). - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
- *    conf.setTimeZoneId("America/Denver");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * Unpaged (whole list) access on a Windows-NT server in a different time zone - * but which has been configured to use a unix-style listing format. - *
- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setTimeZoneId("America/Denver");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * @since 1.4 - * @see org.apache.commons.net.ftp.Configurable - * @see org.apache.commons.net.ftp.FTPClient - * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) - * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl - */ -public class FTPClientConfig -{ - - /** - * Identifier by which a unix-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_UNIX = "UNIX"; - - /** - * Identifier by which a vms-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_VMS = "VMS"; - - /** - * Identifier by which a WindowsNT-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_NT = "WINDOWS"; - - /** - * Identifier by which an OS/2-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_OS2 = "OS/2"; - - /** - * Identifier by which an OS/400-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_OS400 = "OS/400"; - - /** - * Identifier by which an AS/400-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_AS400 = "AS/400"; - - /** - * Identifier by which an MVS-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_MVS = "MVS"; - - /** - * Some servers return an "UNKNOWN Type: L8" message - * in response to the SYST command. We set these to be a Unix-type system. - * This may happen if the ftpd in question was compiled without system - * information. - * - * NET-230 - Updated to be UPPERCASE so that the check done in - * createFileEntryParser will succeed. - * - * @since 1.5 - */ - public static final String SYST_L8 = "TYPE: L8"; - - /** - * Identifier by which an Netware-based ftp server is known throughout - * the commons-net ftp system. - * - * @since 1.5 - */ - public static final String SYST_NETWARE = "NETWARE"; - - private final String serverSystemKey; - private String defaultDateFormatStr = null; - private String recentDateFormatStr = null; - private boolean lenientFutureDates = false; - private String serverLanguageCode = null; - private String shortMonthNames = null; - private String serverTimeZoneId = null; - - - /** - * The main constructor for an FTPClientConfig object - * @param systemKey key representing system type of the server being - * connected to. See {@link #getServerSystemKey() serverSystemKey} - */ - public FTPClientConfig(String systemKey) { - this.serverSystemKey = systemKey; - } - - /** - * Convenience constructor mainly for use in testing. - * Constructs a UNIX configuration. - */ - public FTPClientConfig() { - this(SYST_UNIX); - } - - /** - * Constructor which allows setting of all member fields - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @param serverLanguageCode See - * {@link #setServerLanguageCode(String) serverLanguageCode} - * @param shortMonthNames See - * {@link #setShortMonthNames(String) shortMonthNames} - * @param serverTimeZoneId See - * {@link #setServerTimeZoneId(String) serverTimeZoneId} - */ - public FTPClientConfig(String systemKey, - String defaultDateFormatStr, - String recentDateFormatStr, - String serverLanguageCode, - String shortMonthNames, - String serverTimeZoneId) - { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.recentDateFormatStr = recentDateFormatStr; - this.serverLanguageCode = serverLanguageCode; - this.shortMonthNames = shortMonthNames; - this.serverTimeZoneId = serverTimeZoneId; - } - - private static Map LANGUAGE_CODE_MAP = new TreeMap(); - static { - - // if there are other commonly used month name encodings which - // correspond to particular locales, please add them here. - - - - // many locales code short names for months as all three letters - // these we handle simply. - LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); - LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); - LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); - LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish - LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese - LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish - LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish - LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian - LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch - LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian - LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian - LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian - LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak - LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian - - - // some don't - LANGUAGE_CODE_MAP.put("fr", - "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french - - } - - /** - * Getter for the serverSystemKey property. This property - * specifies the general type of server to which the client connects. - * Should be either one of the FTPClientConfig.SYST_* codes - * or else the fully qualified class name of a parser implementing both - * the FTPFileEntryParser and Configurable - * interfaces. - * @return Returns the serverSystemKey property. - */ - public String getServerSystemKey() { - return serverSystemKey; - } - - /** - * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * property. - * @return Returns the defaultDateFormatStr property. - */ - public String getDefaultDateFormatStr() { - return defaultDateFormatStr; - } - - /** - * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. - * @return Returns the recentDateFormatStr property. - */ - - public String getRecentDateFormatStr() { - return recentDateFormatStr; - } - - /** - * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. - * @return Returns the serverTimeZoneId property. - */ - public String getServerTimeZoneId() { - return serverTimeZoneId; - } - - /** - *

- * getter for the {@link #setShortMonthNames(String) shortMonthNames} - * property. - *

- * @return Returns the shortMonthNames. - */ - public String getShortMonthNames() { - return shortMonthNames; - } - - /** - *

- * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. - *

- * @return Returns the serverLanguageCode property. - */ - public String getServerLanguageCode() { - return serverLanguageCode; - } - - /** - *

- * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. - *

- * @return Returns the lenientFutureDates. - * @since 1.5 - */ - public boolean isLenientFutureDates() { - return lenientFutureDates; - } - /** - *

- * setter for the defaultDateFormatStr property. This property - * specifies the main date format that will be used by a parser configured - * by this configuration to parse file timestamps. If this is not - * specified, such a parser will use as a default value, the most commonly - * used format which will be in as used in en_US locales. - *

- * This should be in the format described for - * java.text.SimpleDateFormat. - * property. - *

- * @param defaultDateFormatStr The defaultDateFormatStr to set. - */ - public void setDefaultDateFormatStr(String defaultDateFormatStr) { - this.defaultDateFormatStr = defaultDateFormatStr; - } - - /** - *

- * setter for the recentDateFormatStr property. This property - * specifies a secondary date format that will be used by a parser - * configured by this configuration to parse file timestamps, typically - * those less than a year old. If this is not specified, such a parser - * will not attempt to parse using an alternate format. - *

- * This is used primarily in unix-based systems. - *

- * This should be in the format described for - * java.text.SimpleDateFormat. - *

- * @param recentDateFormatStr The recentDateFormatStr to set. - */ - public void setRecentDateFormatStr(String recentDateFormatStr) { - this.recentDateFormatStr = recentDateFormatStr; - } - - /** - *

- * setter for the lenientFutureDates property. This boolean property - * (default: false) only has meaning when a - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} property - * has been set. In that case, if this property is set true, then the - * parser, when it encounters a listing parseable with the recent date - * format, will only consider a date to belong to the previous year if - * it is more than one day in the future. This will allow all - * out-of-synch situations (whether based on "slop" - i.e. servers simply - * out of synch with one another or because of time zone differences - - * but in the latter case it is highly recommended to use the - * {@link #setServerTimeZoneId(String) serverTimeZoneId} property - * instead) to resolve correctly. - *

- * This is used primarily in unix-based systems. - *

- * @param lenientFutureDates set true to compensate for out-of-synch - * conditions. - */ - public void setLenientFutureDates(boolean lenientFutureDates) { - this.lenientFutureDates = lenientFutureDates; - } - /** - *

- * setter for the serverTimeZoneId property. This property - * allows a time zone to be specified corresponding to that known to be - * used by an FTP server in file listings. This might be particularly - * useful to clients such as Ant that try to use these timestamps for - * dependency checking. - *

- * This should be one of the identifiers used by - * java.util.TimeZone to refer to time zones, for example, - * America/Chicago or Asia/Rangoon. - *

- * @param serverTimeZoneId The serverTimeZoneId to set. - */ - public void setServerTimeZoneId(String serverTimeZoneId) { - this.serverTimeZoneId = serverTimeZoneId; - } - - /** - *

- * setter for the shortMonthNames property. - * This property allows the user to specify a set of month names - * used by the server that is different from those that may be - * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} - * property. - *

- * This should be a string containing twelve strings each composed of - * three characters, delimited by pipe (|) characters. Currently, - * only 8-bit ASCII characters are known to be supported. For example, - * a set of month names used by a hypothetical Icelandic FTP server might - * conceivably be specified as - * "jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des". - *

- * @param shortMonthNames The value to set to the shortMonthNames property. - */ - public void setShortMonthNames(String shortMonthNames) { - this.shortMonthNames = shortMonthNames; - } - - /** - *

- * setter for the serverLanguageCode property. This property allows - * user to specify a - * - * two-letter ISO-639 language code that will be used to - * configure the set of month names used by the file timestamp parser. - * If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} - * is specified, parsing will assume English month names, which may or - * may not be significant, depending on whether the date format(s) - * specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using - * numeric or alphabetic month names. - *

- *

If the code supplied is not supported here, en_US - * month names will be used. We are supporting here those language - * codes which, when a java.util.Locale is constucted - * using it, and a java.text.SimpleDateFormat is - * constructed using that Locale, the array returned by the - * SimpleDateFormat's getShortMonths() method consists - * solely of three 8-bit ASCII character strings. Additionally, - * languages which do not meet this requirement are included if a - * common alternative set of short month names is known to be used. - * This means that users who can tell us of additional such encodings - * may get them added to the list of supported languages by contacting - * the jakarta-commons-net team. - *

- *

- * Please note that this attribute will NOT be used to determine a - * locale-based date format for the language. - * Experience has shown that many if not most FTP servers outside the - * United States employ the standard en_US date format - * orderings of MMM d yyyy and MMM d HH:mm - * and attempting to deduce this automatically here would cause more - * problems than it would solve. The date format must be changed - * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. - *

- * @param serverLanguageCode The value to set to the serverLanguageCode property. - */ - public void setServerLanguageCode(String serverLanguageCode) { - this.serverLanguageCode = serverLanguageCode; - } - - /** - * Looks up the supplied language code in the internally maintained table of - * language codes. Returns a DateFormatSymbols object configured with - * short month names corresponding to the code. If there is no corresponding - * entry in the table, the object returned will be that for - * Locale.US - * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} - * @return a DateFormatSymbols object configured with short month names - * corresponding to the supplied code, or with month names for - * Locale.US if there is no corresponding entry in the internal - * table. - */ - public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) - { - Object lang = LANGUAGE_CODE_MAP.get(languageCode); - if (lang != null) { - if (lang instanceof Locale) { - return new DateFormatSymbols((Locale) lang); - } else if (lang instanceof String){ - return getDateFormatSymbols((String) lang); - } - } - return new DateFormatSymbols(Locale.US); - } - - /** - * Returns a DateFormatSymbols object configured with short month names - * as in the supplied string - * @param shortmonths This should be as described in - * {@link #setShortMonthNames(String) shortMonthNames} - * @return a DateFormatSymbols object configured with short month names - * as in the supplied string - */ - public static DateFormatSymbols getDateFormatSymbols(String shortmonths) - { - String[] months = splitShortMonthString(shortmonths); - DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); - dfs.setShortMonths(months); - return dfs; - } - - private static String[] splitShortMonthString(String shortmonths) { - StringTokenizer st = new StringTokenizer(shortmonths, "|"); - int monthcnt = st.countTokens(); - if (12 != monthcnt) { - throw new IllegalArgumentException( - "expecting a pipe-delimited string containing 12 tokens"); - } - String[] months = new String[13]; - int pos = 0; - while(st.hasMoreTokens()) { - months[pos++] = st.nextToken(); - } - months[pos]=""; - return months; - } - - /** - * Returns a Collection of all the language codes currently supported - * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} - * for a functional descrption of language codes within this system. - * - * @return a Collection of all the language codes currently supported - * by this class - */ - public static Collection getSupportedLanguageCodes() { - return LANGUAGE_CODE_MAP.keySet(); - } - - -} diff --git a/org/apache/commons/net/ftp/FTPCommand.class b/org/apache/commons/net/ftp/FTPCommand.class deleted file mode 100644 index 15c59a3..0000000 Binary files a/org/apache/commons/net/ftp/FTPCommand.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPCommand.java b/org/apache/commons/net/ftp/FTPCommand.java deleted file mode 100644 index d016dff..0000000 --- a/org/apache/commons/net/ftp/FTPCommand.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -/*** - * FTPCommand stores a set of constants for FTP command codes. To interpret - * the meaning of the codes, familiarity with RFC 959 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 959. For those who think in terms of the actual FTP commands, - * a set of constants such as {@link #USER USER } are provided - * where the constant name is the same as the FTP command. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class FTPCommand -{ - - - public static final int USER = 0; - public static final int PASS = 1; - public static final int ACCT = 2; - public static final int CWD = 3; - public static final int CDUP = 4; - public static final int SMNT = 5; - public static final int REIN = 6; - public static final int QUIT = 7; - public static final int PORT = 8; - public static final int PASV = 9; - public static final int TYPE = 10; - public static final int STRU = 11; - public static final int MODE = 12; - public static final int RETR = 13; - public static final int STOR = 14; - public static final int STOU = 15; - public static final int APPE = 16; - public static final int ALLO = 17; - public static final int REST = 18; - public static final int RNFR = 19; - public static final int RNTO = 20; - public static final int ABOR = 21; - public static final int DELE = 22; - public static final int RMD = 23; - public static final int MKD = 24; - public static final int PWD = 25; - public static final int LIST = 26; - public static final int NLST = 27; - public static final int SITE = 28; - public static final int SYST = 29; - public static final int STAT = 30; - public static final int HELP = 31; - public static final int NOOP = 32; - /** @since 2.0 */ - public static final int MDTM = 33; - - public static final int USERNAME = USER; - public static final int PASSWORD = PASS; - public static final int ACCOUNT = ACCT; - public static final int CHANGE_WORKING_DIRECTORY = CWD; - public static final int CHANGE_TO_PARENT_DIRECTORY = CDUP; - public static final int STRUCTURE_MOUNT = SMNT; - public static final int REINITIALIZE = REIN; - public static final int LOGOUT = QUIT; - public static final int DATA_PORT = PORT; - public static final int PASSIVE = PASV; - public static final int REPRESENTATION_TYPE = TYPE; - public static final int FILE_STRUCTURE = STRU; - public static final int TRANSFER_MODE = MODE; - public static final int RETRIEVE = RETR; - public static final int STORE = STOR; - public static final int STORE_UNIQUE = STOU; - public static final int APPEND = APPE; - public static final int ALLOCATE = ALLO; - public static final int RESTART = REST; - public static final int RENAME_FROM = RNFR; - public static final int RENAME_TO = RNTO; - public static final int ABORT = ABOR; - public static final int DELETE = DELE; - public static final int REMOVE_DIRECTORY = RMD; - public static final int MAKE_DIRECTORY = MKD; - public static final int PRINT_WORKING_DIRECTORY = PWD; - // public static final int LIST = LIST; - public static final int NAME_LIST = NLST; - public static final int SITE_PARAMETERS = SITE; - public static final int SYSTEM = SYST; - public static final int STATUS = STAT; - //public static final int HELP = HELP; - //public static final int NOOP = NOOP; - /** @since 2.0 */ - public static final int MOD_TIME = MDTM; - - // Cannot be instantiated - private FTPCommand() - {} - - static final String[] _commands = { - "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", - "PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", - "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", - "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP" - }; - - /** - * Retrieve the FTP protocol command string corresponding to a specified - * command code. - *

- * @param command The command code. - * @return The FTP protcol command string corresponding to a specified - * command code. - */ - public static final String getCommand(int command) - { - return _commands[command]; - } -} diff --git a/org/apache/commons/net/ftp/FTPConnectionClosedException.class b/org/apache/commons/net/ftp/FTPConnectionClosedException.class deleted file mode 100644 index 38004cb..0000000 Binary files a/org/apache/commons/net/ftp/FTPConnectionClosedException.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPConnectionClosedException.java b/org/apache/commons/net/ftp/FTPConnectionClosedException.java deleted file mode 100644 index 3eccbf4..0000000 --- a/org/apache/commons/net/ftp/FTPConnectionClosedException.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.IOException; - -/*** - * FTPConnectionClosedException is used to indicate the premature or - * unexpected closing of an FTP connection resulting from a - * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response (FTP reply code 421) to a - * failed FTP command. This exception is derived from IOException and - * therefore may be caught either as an IOException or specifically as an - * FTPConnectionClosedException. - *

- *

- * @author Daniel F. Savarese - * @see FTP - * @see FTPClient - ***/ - -public class FTPConnectionClosedException extends IOException -{ - - /*** Constructs a FTPConnectionClosedException with no message ***/ - public FTPConnectionClosedException() - { - super(); - } - - /*** - * Constructs a FTPConnectionClosedException with a specified message. - *

- * @param message The message explaining the reason for the exception. - ***/ - public FTPConnectionClosedException(String message) - { - super(message); - } - -} diff --git a/org/apache/commons/net/ftp/FTPFile.class b/org/apache/commons/net/ftp/FTPFile.class deleted file mode 100644 index 6cb7744..0000000 Binary files a/org/apache/commons/net/ftp/FTPFile.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPFile.java b/org/apache/commons/net/ftp/FTPFile.java deleted file mode 100644 index dd67904..0000000 --- a/org/apache/commons/net/ftp/FTPFile.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.Serializable; -import java.util.Calendar; - -/*** - * The FTPFile class is used to represent information about files stored - * on an FTP server. Because there is no standard representation for - * file information on FTP servers, it may not always be possible to - * extract all the information that can be represented by FTPFile, or - * it may even be possible to extract more information. In cases where - * more information can be extracted, you will want to subclass FTPFile - * and implement your own {@link org.apache.commons.net.ftp.FTPFileListParser} - * to extract the information. - * However, most FTP servers return file information in a format that - * can be completely parsed by - * {@link org.apache.commons.net.ftp.DefaultFTPFileListParser} - * and stored in FTPFile. - *

- *

- * @author Daniel F. Savarese - * @see FTPFileListParser - * @see DefaultFTPFileListParser - * @see FTPClient#listFiles - ***/ - -public class FTPFile implements Serializable -{ - /** A constant indicating an FTPFile is a file. ***/ - public static final int FILE_TYPE = 0; - /** A constant indicating an FTPFile is a directory. ***/ - public static final int DIRECTORY_TYPE = 1; - /** A constant indicating an FTPFile is a symbolic link. ***/ - public static final int SYMBOLIC_LINK_TYPE = 2; - /** A constant indicating an FTPFile is of unknown type. ***/ - public static final int UNKNOWN_TYPE = 3; - - /** A constant indicating user access permissions. ***/ - public static final int USER_ACCESS = 0; - /** A constant indicating group access permissions. ***/ - public static final int GROUP_ACCESS = 1; - /** A constant indicating world access permissions. ***/ - public static final int WORLD_ACCESS = 2; - - /** A constant indicating file/directory read permission. ***/ - public static final int READ_PERMISSION = 0; - /** A constant indicating file/directory write permission. ***/ - public static final int WRITE_PERMISSION = 1; - /** - * A constant indicating file execute permission or directory listing - * permission. - ***/ - public static final int EXECUTE_PERMISSION = 2; - - int _type, _hardLinkCount; - long _size; - String _rawListing, _user, _group, _name, _link; - Calendar _date; - boolean[] _permissions[]; - - /*** Creates an empty FTPFile. ***/ - public FTPFile() - { - _permissions = new boolean[3][3]; - _rawListing = null; - _type = UNKNOWN_TYPE; - _hardLinkCount = 0; - _size = 0; - _user = null; - _group = null; - _date = null; - _name = null; - } - - - /*** - * Set the original FTP server raw listing from which the FTPFile was - * created. - *

- * @param rawListing The raw FTP server listing. - ***/ - public void setRawListing(String rawListing) - { - _rawListing = rawListing; - } - - /*** - * Get the original FTP server raw listing used to initialize the FTPFile. - *

- * @return The original FTP server raw listing used to initialize the - * FTPFile. - ***/ - public String getRawListing() - { - return _rawListing; - } - - - /*** - * Determine if the file is a directory. - *

- * @return True if the file is of type DIRECTORY_TYPE, false if - * not. - ***/ - public boolean isDirectory() - { - return (_type == DIRECTORY_TYPE); - } - - /*** - * Determine if the file is a regular file. - *

- * @return True if the file is of type FILE_TYPE, false if - * not. - ***/ - public boolean isFile() - { - return (_type == FILE_TYPE); - } - - /*** - * Determine if the file is a symbolic link. - *

- * @return True if the file is of type UNKNOWN_TYPE, false if - * not. - ***/ - public boolean isSymbolicLink() - { - return (_type == SYMBOLIC_LINK_TYPE); - } - - /*** - * Determine if the type of the file is unknown. - *

- * @return True if the file is of type UNKNOWN_TYPE, false if - * not. - ***/ - public boolean isUnknown() - { - return (_type == UNKNOWN_TYPE); - } - - - /*** - * Set the type of the file (DIRECTORY_TYPE, - * FILE_TYPE, etc.). - *

- * @param type The integer code representing the type of the file. - ***/ - public void setType(int type) - { - _type = type; - } - - - /*** - * Return the type of the file (one of the _TYPE constants), - * e.g., if it is a directory, a regular file, or a symbolic link. - *

- * @return The type of the file. - ***/ - public int getType() - { - return _type; - } - - - /*** - * Set the name of the file. - *

- * @param name The name of the file. - ***/ - public void setName(String name) - { - _name = name; - } - - /*** - * Return the name of the file. - *

- * @return The name of the file. - ***/ - public String getName() - { - return _name; - } - - - /** - * Set the file size in bytes. - * @param size The file size in bytes. - */ - public void setSize(long size) - { - _size = size; - } - - - /*** - * Return the file size in bytes. - *

- * @return The file size in bytes. - ***/ - public long getSize() - { - return _size; - } - - - /*** - * Set the number of hard links to this file. This is not to be - * confused with symbolic links. - *

- * @param links The number of hard links to this file. - ***/ - public void setHardLinkCount(int links) - { - _hardLinkCount = links; - } - - - /*** - * Return the number of hard links to this file. This is not to be - * confused with symbolic links. - *

- * @return The number of hard links to this file. - ***/ - public int getHardLinkCount() - { - return _hardLinkCount; - } - - - /*** - * Set the name of the group owning the file. This may be - * a string representation of the group number. - *

- * @param group The name of the group owning the file. - ***/ - public void setGroup(String group) - { - _group = group; - } - - - /*** - * Returns the name of the group owning the file. Sometimes this will be - * a string representation of the group number. - *

- * @return The name of the group owning the file. - ***/ - public String getGroup() - { - return _group; - } - - - /*** - * Set the name of the user owning the file. This may be - * a string representation of the user number; - *

- * @param user The name of the user owning the file. - ***/ - public void setUser(String user) - { - _user = user; - } - - /*** - * Returns the name of the user owning the file. Sometimes this will be - * a string representation of the user number. - *

- * @return The name of the user owning the file. - ***/ - public String getUser() - { - return _user; - } - - - /*** - * If the FTPFile is a symbolic link, use this method to set the name of the - * file being pointed to by the symbolic link. - *

- * @param link The file pointed to by the symbolic link. - ***/ - public void setLink(String link) - { - _link = link; - } - - - /*** - * If the FTPFile is a symbolic link, this method returns the name of the - * file being pointed to by the symbolic link. Otherwise it returns null. - *

- * @return The file pointed to by the symbolic link (null if the FTPFile - * is not a symbolic link). - ***/ - public String getLink() - { - return _link; - } - - - /*** - * Set the file timestamp. This usually the last modification time. - * The parameter is not cloned, so do not alter its value after calling - * this method. - *

- * @param date A Calendar instance representing the file timestamp. - ***/ - public void setTimestamp(Calendar date) - { - _date = date; - } - - - /*** - * Returns the file timestamp. This usually the last modification time. - *

- * @return A Calendar instance representing the file timestamp. - ***/ - public Calendar getTimestamp() - { - return _date; - } - - - /*** - * Set if the given access group (one of the _ACCESS - * constants) has the given access permission (one of the - * _PERMISSION constants) to the file. - *

- * @param access The access group (one of the _ACCESS - * constants) - * @param permission The access permission (one of the - * _PERMISSION constants) - * @param value True if permission is allowed, false if not. - ***/ - public void setPermission(int access, int permission, boolean value) - { - _permissions[access][permission] = value; - } - - - /*** - * Determines if the given access group (one of the _ACCESS - * constants) has the given access permission (one of the - * _PERMISSION constants) to the file. - *

- * @param access The access group (one of the _ACCESS - * constants) - * @param permission The access permission (one of the - * _PERMISSION constants) - ***/ - public boolean hasPermission(int access, int permission) - { - return _permissions[access][permission]; - } - - - /*** - * Returns a string representation of the FTPFile information. This - * will be the raw FTP server listing that was used to initialize the - * FTPFile instance. - *

- * @return A string representation of the FTPFile information. - ***/ - @Override - public String toString() - { - return _rawListing; - } - -} diff --git a/org/apache/commons/net/ftp/FTPFileEntryParser.class b/org/apache/commons/net/ftp/FTPFileEntryParser.class deleted file mode 100644 index 2643bb2..0000000 Binary files a/org/apache/commons/net/ftp/FTPFileEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPFileEntryParser.java b/org/apache/commons/net/ftp/FTPFileEntryParser.java deleted file mode 100644 index 8e6d09c..0000000 --- a/org/apache/commons/net/ftp/FTPFileEntryParser.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedReader; -import java.io.IOException; -import java.util.List; - -/** - * FTPFileEntryParser defines the interface for parsing a single FTP file - * listing and converting that information into an - * {@link org.apache.commons.net.ftp.FTPFile} instance. - * Sometimes you will want to parse unusual listing formats, in which - * case you would create your own implementation of FTPFileEntryParser and - * if necessary, subclass FTPFile. - *

- * Here are some examples showing how to use one of the classes that - * implement this interface. - *

- * The first example shows how to get an iterable list of files in which the - * more expensive FTPFile objects are not created until needed. This - * is suitable for paged displays. It requires that a parser object be created - * beforehand: parser is an object (in the package - * org.apache.commons.net.ftp.parser) - * implementing this inteface. - * - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFileList list = f.createFileList(directory, parser);
- *    FTPFileIterator iter = list.iterator();
- *
- *    while (iter.hasNext()) {
- *       FTPFile[] files = iter.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- * - * The second example uses the revised FTPClient.listFiles() - * API to pull the whole list from the subfolder subfolder in - * one call, attempting to automatically detect the parser type. This - * method, without a parserKey parameter, indicates that autodection should - * be used. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles("subfolder");
- * 
- * - * The third example uses the revised FTPClient.listFiles()> - * API to pull the whole list from the current working directory in one call, - * but specifying by classname the parser to be used. For this particular - * parser class, this approach is necessary since there is no way to - * autodetect this server type. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles(
- *      "org.apache.commons.net.ftp.parser.EnterpriseUnixFTPFileEntryParser",
- *      ".");
- * 
- * - * The fourth example uses the revised FTPClient.listFiles() - * API to pull a single file listing in an arbitrary directory in one call, - * specifying by KEY the parser to be used, in this case, VMS. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles("VMS", "subfolder/foo.java");
- * 
- * - * @author Steve Cohen - * @version $Id: FTPFileEntryParser.java 636854 2008-03-13 19:55:01Z sebb $ - * @see org.apache.commons.net.ftp.FTPFile - * @see org.apache.commons.net.ftp.FTPClient#createFileList - */ -public interface FTPFileEntryParser -{ - /** - * Parses a line of an FTP server file listing and converts it into a usable - * format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null should be - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- * @param listEntry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - FTPFile parseFTPEntry(String listEntry); - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. Implementors must define - * this for the particular ftp system being parsed. In many but not all - * cases, this can be defined simply by calling BufferedReader.readLine(). - * - * @param reader The BufferedReader object from which entries are to be - * read. - * - * @return A string representing the next ftp entry or null if none found. - * @exception IOException thrown on any IO Error reading from the reader. - */ - String readNextEntry(BufferedReader reader) throws IOException; - - - /** - * This method is a hook for those implementors (such as - * VMSVersioningFTPEntryParser, and possibly others) which need to - * perform some action upon the FTPFileList after it has been created - * from the server stream, but before any clients see the list. - * - * The default implementation can be a no-op. - * - * @param original Original list after it has been created from the server stream - * - * @return Original list as processed by this method. - */ - List preParse(List original); - - -} - - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class b/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class deleted file mode 100644 index aee0145..0000000 Binary files a/org/apache/commons/net/ftp/FTPFileEntryParserImpl.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java b/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java deleted file mode 100644 index 22214fe..0000000 --- a/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedReader; -import java.io.IOException; -import java.util.Iterator; -import java.util.List; - -/** - * This abstract class implements both the older FTPFileListParser and - * newer FTPFileEntryParser interfaces with default functionality. - * All the classes in the parser subpackage inherit from this. - * - */ -public abstract class FTPFileEntryParserImpl - implements FTPFileEntryParser -{ - /** - * The constructor for a FTPFileEntryParserImpl object. - */ - public FTPFileEntryParserImpl() - { - } - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. This default implementation - * simply calls BufferedReader.readLine(). - * - * @param reader The BufferedReader object from which entries are to be - * read. - * - * @return A string representing the next ftp entry or null if none found. - * @exception java.io.IOException thrown on any IO Error reading from the reader. - */ - public String readNextEntry(BufferedReader reader) throws IOException - { - return reader.readLine(); - } - /** - * This method is a hook for those implementors (such as - * VMSVersioningFTPEntryParser, and possibly others) which need to - * perform some action upon the FTPFileList after it has been created - * from the server stream, but before any clients see the list. - * - * This default implementation removes entries that do not parse as files. - * - * @param original Original list after it has been created from the server stream - * - * @return original unmodified. - */ - public List preParse(List original) { - Iterator it = original.iterator(); - while (it.hasNext()){ - String entry = it.next(); - if (null == parseFTPEntry(entry)) { - it.remove(); - } - } - return original; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/ftp/FTPListParseEngine.class b/org/apache/commons/net/ftp/FTPListParseEngine.class deleted file mode 100644 index cc23486..0000000 Binary files a/org/apache/commons/net/ftp/FTPListParseEngine.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPListParseEngine.java b/org/apache/commons/net/ftp/FTPListParseEngine.java deleted file mode 100644 index 468bf39..0000000 --- a/org/apache/commons/net/ftp/FTPListParseEngine.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; - - -/** - * This class handles the entire process of parsing a listing of - * file entries from the server. - *

- * This object defines a two-part parsing mechanism. - *

- * The first part is comprised of reading the raw input into an internal - * list of strings. Every item in this list corresponds to an actual - * file. All extraneous matter emitted by the server will have been - * removed by the end of this phase. This is accomplished in conjunction - * with the FTPFileEntryParser associated with this engine, by calling - * its methods readNextEntry() - which handles the issue of - * what delimits one entry from another, usually but not always a line - * feed and preParse() - which handles removal of - * extraneous matter such as the preliminary lines of a listing, removal - * of duplicates on versioning systems, etc. - *

- * The second part is composed of the actual parsing, again in conjunction - * with the particular parser used by this engine. This is controlled - * by an iterator over the internal list of strings. This may be done - * either in block mode, by calling the getNext() and - * getPrevious() methods to provide "paged" output of less - * than the whole list at one time, or by calling the - * getFiles() method to return the entire list. - *

- * Examples: - *

- * Paged access: - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine = f.initiateListParsing(directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * For unpaged access, simply use FTPClient.listFiles(). That method - * uses this class transparently. - * @version $Id: FTPListParseEngine.java 658518 2008-05-21 01:04:30Z sebb $ - */ -public class FTPListParseEngine { - private List entries = new LinkedList(); - private ListIterator _internalIterator = entries.listIterator(); - - FTPFileEntryParser parser = null; - - public FTPListParseEngine(FTPFileEntryParser parser) { - this.parser = parser; - } - - /** - * handle the iniitial reading and preparsing of the list returned by - * the server. After this method has completed, this object will contain - * a list of unparsed entries (Strings) each referring to a unique file - * on the server. - * - * @param stream input stream provided by the server socket. - * - * @exception IOException - * thrown on any failure to read from the sever. - */ - public void readServerList(InputStream stream, String encoding) - throws IOException - { - this.entries = new LinkedList(); - readStream(stream, encoding); - this.parser.preParse(this.entries); - resetIterator(); - } - - /** - * handle the iniitial reading and preparsing of the list returned by - * the server. After this method has completed, this object will contain - * a list of unparsed entries (Strings) each referring to a unique file - * on the server. - * - * @param stream input stream provided by the server socket. - * - * @exception IOException - * thrown on any failure to read from the sever. - * - * @deprecated The version of this method which takes an encoding should be used. - */ - public void readServerList(InputStream stream) - throws IOException - { - readServerList(stream, null); - } - - - - /** - * Internal method for reading the input into the entries list. - * After this method has completed, entries will contain a - * collection of entries (as defined by - * FTPFileEntryParser.readNextEntry()), but this may contain - * various non-entry preliminary lines from the server output, duplicates, - * and other data that will not be part of the final listing. - * - * @param stream The socket stream on which the input will be read. - * @param encoding The encoding to use. - * - * @exception IOException - * thrown on any failure to read the stream - */ - private void readStream(InputStream stream, String encoding) throws IOException - { - BufferedReader reader; - if (encoding == null) - { - reader = new BufferedReader(new InputStreamReader(stream)); - } - else - { - reader = new BufferedReader(new InputStreamReader(stream, encoding)); - } - - String line = this.parser.readNextEntry(reader); - - while (line != null) - { - this.entries.add(line); - line = this.parser.readNextEntry(reader); - } - reader.close(); - } - - /** - * Returns an array of at most quantityRequested FTPFile - * objects starting at this object's internal iterator's current position. - * If fewer than quantityRequested such - * elements are available, the returned array will have a length equal - * to the number of entries at and after after the current position. - * If no such entries are found, this array will have a length of 0. - * - * After this method is called this object's internal iterator is advanced - * by a number of positions equal to the size of the array returned. - * - * @param quantityRequested - * the maximum number of entries we want to get. - * - * @return an array of at most quantityRequested FTPFile - * objects starting at the current position of this iterator within its - * list and at least the number of elements which exist in the list at - * and after its current position. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - */ - public FTPFile[] getNext(int quantityRequested) { - List tmpResults = new LinkedList(); - int count = quantityRequested; - while (count > 0 && this._internalIterator.hasNext()) { - String entry = this._internalIterator.next(); - FTPFile temp = this.parser.parseFTPEntry(entry); - tmpResults.add(temp); - count--; - } - return tmpResults.toArray(new FTPFile[0]); - - } - - /** - * Returns an array of at most quantityRequested FTPFile - * objects starting at this object's internal iterator's current position, - * and working back toward the beginning. - * - * If fewer than quantityRequested such - * elements are available, the returned array will have a length equal - * to the number of entries at and after after the current position. - * If no such entries are found, this array will have a length of 0. - * - * After this method is called this object's internal iterator is moved - * back by a number of positions equal to the size of the array returned. - * - * @param quantityRequested - * the maximum number of entries we want to get. - * - * @return an array of at most quantityRequested FTPFile - * objects starting at the current position of this iterator within its - * list and at least the number of elements which exist in the list at - * and after its current position. This array will be in the same order - * as the underlying list (not reversed). - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - */ - public FTPFile[] getPrevious(int quantityRequested) { - List tmpResults = new LinkedList(); - int count = quantityRequested; - while (count > 0 && this._internalIterator.hasPrevious()) { - String entry = this._internalIterator.previous(); - FTPFile temp = this.parser.parseFTPEntry(entry); - tmpResults.add(0,temp); - count--; - } - return tmpResults.toArray(new FTPFile[0]); - } - - /** - * Returns an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * - * @return an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - * @exception IOException - */ - public FTPFile[] getFiles() - throws IOException - { - List tmpResults = new LinkedList(); - Iterator iter = this.entries.iterator(); - while (iter.hasNext()) { - String entry = iter.next(); - FTPFile temp = this.parser.parseFTPEntry(entry); - tmpResults.add(temp); - } - return tmpResults.toArray(new FTPFile[0]); - - } - - /** - * convenience method to allow clients to know whether this object's - * internal iterator's current position is at the end of the list. - * - * @return true if internal iterator is not at end of list, false - * otherwise. - */ - public boolean hasNext() { - return _internalIterator.hasNext(); - } - - /** - * convenience method to allow clients to know whether this object's - * internal iterator's current position is at the beginning of the list. - * - * @return true if internal iterator is not at beginning of list, false - * otherwise. - */ - public boolean hasPrevious() { - return _internalIterator.hasPrevious(); - } - - /** - * resets this object's internal iterator to the beginning of the list. - */ - public void resetIterator() { - this._internalIterator = this.entries.listIterator(); - } -} diff --git a/org/apache/commons/net/ftp/FTPReply.class b/org/apache/commons/net/ftp/FTPReply.class deleted file mode 100644 index 2d596ba..0000000 Binary files a/org/apache/commons/net/ftp/FTPReply.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/FTPReply.java b/org/apache/commons/net/ftp/FTPReply.java deleted file mode 100644 index 6386568..0000000 --- a/org/apache/commons/net/ftp/FTPReply.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -/*** - * FTPReply stores a set of constants for FTP reply codes. To interpret - * the meaning of the codes, familiarity with RFC 959 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 959. For those who think in terms of the actual reply code values, - * a set of CODE_NUM constants are provided where NUM is the numerical value - * of the code. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class FTPReply -{ - - public static final int CODE_110 = 110; - public static final int CODE_120 = 120; - public static final int CODE_125 = 125; - public static final int CODE_150 = 150; - public static final int CODE_200 = 200; - public static final int CODE_202 = 202; - public static final int CODE_211 = 211; - public static final int CODE_212 = 212; - public static final int CODE_213 = 213; - public static final int CODE_214 = 214; - public static final int CODE_215 = 215; - public static final int CODE_220 = 220; - public static final int CODE_221 = 221; - public static final int CODE_225 = 225; - public static final int CODE_226 = 226; - public static final int CODE_227 = 227; - public static final int CODE_230 = 230; - public static final int CODE_250 = 250; - public static final int CODE_257 = 257; - public static final int CODE_331 = 331; - public static final int CODE_332 = 332; - public static final int CODE_350 = 350; - public static final int CODE_421 = 421; - public static final int CODE_425 = 425; - public static final int CODE_426 = 426; - public static final int CODE_450 = 450; - public static final int CODE_451 = 451; - public static final int CODE_452 = 452; - public static final int CODE_500 = 500; - public static final int CODE_501 = 501; - public static final int CODE_502 = 502; - public static final int CODE_503 = 503; - public static final int CODE_504 = 504; - public static final int CODE_521 = 521; - public static final int CODE_530 = 530; - public static final int CODE_532 = 532; - public static final int CODE_550 = 550; - public static final int CODE_551 = 551; - public static final int CODE_552 = 552; - public static final int CODE_553 = 553; - - public static final int RESTART_MARKER = CODE_110; - public static final int SERVICE_NOT_READY = CODE_120; - public static final int DATA_CONNECTION_ALREADY_OPEN = CODE_125; - public static final int FILE_STATUS_OK = CODE_150; - public static final int COMMAND_OK = CODE_200; - public static final int COMMAND_IS_SUPERFLUOUS = CODE_202; - public static final int SYSTEM_STATUS = CODE_211; - public static final int DIRECTORY_STATUS = CODE_212; - public static final int FILE_STATUS = CODE_213; - public static final int HELP_MESSAGE = CODE_214; - public static final int NAME_SYSTEM_TYPE = CODE_215; - public static final int SERVICE_READY = CODE_220; - public static final int SERVICE_CLOSING_CONTROL_CONNECTION = CODE_221; - public static final int DATA_CONNECTION_OPEN = CODE_225; - public static final int CLOSING_DATA_CONNECTION = CODE_226; - public static final int ENTERING_PASSIVE_MODE = CODE_227; - public static final int USER_LOGGED_IN = CODE_230; - public static final int FILE_ACTION_OK = CODE_250; - public static final int PATHNAME_CREATED = CODE_257; - public static final int NEED_PASSWORD = CODE_331; - public static final int NEED_ACCOUNT = CODE_332; - public static final int FILE_ACTION_PENDING = CODE_350; - public static final int SERVICE_NOT_AVAILABLE = CODE_421; - public static final int CANNOT_OPEN_DATA_CONNECTION = CODE_425; - public static final int TRANSFER_ABORTED = CODE_426; - public static final int FILE_ACTION_NOT_TAKEN = CODE_450; - public static final int ACTION_ABORTED = CODE_451; - public static final int INSUFFICIENT_STORAGE = CODE_452; - public static final int UNRECOGNIZED_COMMAND = CODE_500; - public static final int SYNTAX_ERROR_IN_ARGUMENTS = CODE_501; - public static final int COMMAND_NOT_IMPLEMENTED = CODE_502; - public static final int BAD_COMMAND_SEQUENCE = CODE_503; - public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = CODE_504; - public static final int NOT_LOGGED_IN = CODE_530; - public static final int NEED_ACCOUNT_FOR_STORING_FILES = CODE_532; - public static final int FILE_UNAVAILABLE = CODE_550; - public static final int PAGE_TYPE_UNKNOWN = CODE_551; - public static final int STORAGE_ALLOCATION_EXCEEDED = CODE_552; - public static final int FILE_NAME_NOT_ALLOWED = CODE_553; - - // FTPS Reply Codes - /** @since 2.0 */ - public static final int CODE_234 = 234; - /** @since 2.0 */ - public static final int CODE_235 = 235; - /** @since 2.0 */ - public static final int CODE_334 = 334; - /** @since 2.0 */ - public static final int CODE_335 = 335; - /** @since 2.0 */ - public static final int CODE_431 = 431; - /** @since 2.0 */ - public static final int CODE_533 = 533; - /** @since 2.0 */ - public static final int CODE_534 = 534; - /** @since 2.0 */ - public static final int CODE_535 = 535; - /** @since 2.0 */ - public static final int CODE_536 = 536; - - /** @since 2.0 */ - public static final int SECURITY_DATA_EXCHANGE_COMPLETE = CODE_234; - /** @since 2.0 */ - public static final int SECURITY_DATA_EXCHANGE_SUCCESSFULLY = CODE_235; - /** @since 2.0 */ - public static final int SECURITY_MECHANISM_IS_OK = CODE_334; - /** @since 2.0 */ - public static final int SECURITY_DATA_IS_ACCEPTABLE = CODE_335; - /** @since 2.0 */ - public static final int UNAVAILABLE_RESOURCE = CODE_431; - /** @since 2.0 */ - public static final int DENIED_FOR_POLICY_REASONS = CODE_533; - /** @since 2.0 */ - public static final int REQUEST_DENIED = CODE_534; - /** @since 2.0 */ - public static final int FAILED_SECURITY_CHECK = CODE_535; - /** @since 2.0 */ - public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = CODE_536; - - - // Cannot be instantiated - private FTPReply() - {} - - /*** - * Determine if a reply code is a positive preliminary response. All - * codes beginning with a 1 are positive preliminary responses. - * Postitive preliminary responses are used to indicate tentative success. - * No further commands can be issued to the FTP server after a positive - * preliminary response until a follow up response is received from the - * server. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive preliminary response, false - * if not. - ***/ - public static boolean isPositivePreliminary(int reply) - { - return (reply >= 100 && reply < 200); - } - - /*** - * Determine if a reply code is a positive completion response. All - * codes beginning with a 2 are positive completion responses. - * The FTP server will send a positive completion response on the final - * successful completion of a command. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive completion response, false - * if not. - ***/ - public static boolean isPositiveCompletion(int reply) - { - return (reply >= 200 && reply < 300); - } - - /*** - * Determine if a reply code is a positive intermediate response. All - * codes beginning with a 3 are positive intermediate responses. - * The FTP server will send a positive intermediate response on the - * successful completion of one part of a multi-part sequence of - * commands. For example, after a successful USER command, a positive - * intermediate response will be sent to indicate that the server is - * ready for the PASS command. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive intermediate response, false - * if not. - ***/ - public static boolean isPositiveIntermediate(int reply) - { - return (reply >= 300 && reply < 400); - } - - /*** - * Determine if a reply code is a negative transient response. All - * codes beginning with a 4 are negative transient responses. - * The FTP server will send a negative transient response on the - * failure of a command that can be reattempted with success. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative transient response, false - * if not. - ***/ - public static boolean isNegativeTransient(int reply) - { - return (reply >= 400 && reply < 500); - } - - /*** - * Determine if a reply code is a negative permanent response. All - * codes beginning with a 5 are negative permanent responses. - * The FTP server will send a negative permanent response on the - * failure of a command that cannot be reattempted with success. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative permanent response, false - * if not. - ***/ - public static boolean isNegativePermanent(int reply) - { - return (reply >= 500 && reply < 600); - } - -} diff --git a/org/apache/commons/net/ftp/FTPSClient.java b/org/apache/commons/net/ftp/FTPSClient.java deleted file mode 100644 index f809c41..0000000 --- a/org/apache/commons/net/ftp/FTPSClient.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.Socket; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -/** - * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to - * see wire-level SSL details. - * - * @version $Id: FTPSClient.java 658520 2008-05-21 01:14:11Z sebb $ - * @since 2.0 - */ -public class FTPSClient extends FTPClient { - - /** keystore algorithm name. */ - public static String KEYSTORE_ALGORITHM; - /** truststore algorithm name. */ - public static String TRUSTSTORE_ALGORITHM; - /** provider name. */ - public static String PROVIDER; - /** truststore type. */ - public static String STORE_TYPE; - - /** The value that I can set in PROT command */ - private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; - /** Default PROT Command */ - private static final String DEFAULT_PROT = "C"; - /** Default protocol name */ - private static final String DEFAULT_PROTOCOL = "TLS"; - - /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ - private boolean isImplicit; - /** The use SSL/TLS protocol. */ - private String protocol = DEFAULT_PROTOCOL; - /** The AUTH Command value */ - private String auth = DEFAULT_PROTOCOL; - /** The context object. */ - private SSLContext context; - /** The socket object. */ - private Socket planeSocket; - /** The established socket flag. */ - private boolean isCreation = true; - /** The use client mode flag. */ - private boolean isClientMode = true; - /** The need client auth flag. */ - private boolean isNeedClientAuth = false; - /** The want client auth flag. */ - private boolean isWantClientAuth = false; - /** The cipher suites */ - private String[] suites = null; - /** The protocol versions */ - private String[] protocols = null; - - /** The FTPS {@link TrustManager} implementation. */ - private TrustManager trustManager = new FTPSTrustManager(); - - /** The {@link KeyManager} */ - private KeyManager keyManager; - - /** - * Constructor for FTPSClient. - * @throws NoSuchAlgorithmException A requested cryptographic algorithm - * is not available in the environment. - */ - public FTPSClient() throws NoSuchAlgorithmException { - this.protocol = DEFAULT_PROTOCOL; - this.isImplicit = false; - } - - /** - * Constructor for FTPSClient. - * @param isImplicit The secutiry mode(Implicit/Explicit). - * @throws NoSuchAlgorithmException A requested cryptographic algorithm - * is not available in the environment. - */ - public FTPSClient(boolean isImplicit) throws NoSuchAlgorithmException { - this.protocol = DEFAULT_PROTOCOL; - this.isImplicit = isImplicit; - } - - /** - * Constructor for FTPSClient. - * @param protocol the protocol - * @throws NoSuchAlgorithmException A requested cryptographic algorithm - * is not available in the environment. - */ - public FTPSClient(String protocol) throws NoSuchAlgorithmException { - this.protocol = protocol; - this.isImplicit = false; - } - - /** - * Constructor for FTPSClient. - * @param protocol the protocol - * @param isImplicit The secutiry mode(Implicit/Explicit). - * @throws NoSuchAlgorithmException A requested cryptographic algorithm - * is not available in the environment. - */ - public FTPSClient(String protocol, boolean isImplicit) - throws NoSuchAlgorithmException { - this.protocol = protocol; - this.isImplicit = isImplicit; - } - - - /** - * Set AUTH command use value. - * This processing is done before connected processing. - * @param auth AUTH command use value. - */ - public void setAuthValue(String auth) { - this.auth = auth; - } - - /** - * Return AUTH command use value. - * @return AUTH command use value. - */ - public String getAuthValue() { - return this.auth; - } - - - /** - * Because there are so many connect() methods, - * the _connectAction_() method is provided as a means of performing - * some action immediately after establishing a connection, - * rather than reimplementing all of the connect() methods. - * @throws IOException If it throw by _connectAction_. - * @see org.apache.commons.net.SocketClient#_connectAction_() - */ - @Override - protected void _connectAction_() throws IOException { - // Implicit mode. - if (isImplicit) sslNegotiation(); - super._connectAction_(); - // Explicit mode. - if (!isImplicit) { - execAUTH(); - sslNegotiation(); - } - } - - /** - * AUTH command. - * @throws SSLException If it server reply code not equal "234" and "334". - * @throws IOException If an I/O error occurs while either sending - * the command. - */ - private void execAUTH() throws SSLException, IOException { - int replyCode = sendCommand( - FTPSCommand._commands[FTPSCommand.AUTH], auth); - if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { - // replyCode = 334 - // I carry out an ADAT command. - } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { - throw new SSLException(getReplyString()); - } - } - - /** - * Performs a lazy init of the SSL context - * @throws IOException - */ - private void initSslContext() throws IOException { - if(context == null) { - try { - context = SSLContext.getInstance(protocol); - - context.init(new KeyManager[] { getKeyManager() } , new TrustManager[] { getTrustManager() } , null); - } catch (KeyManagementException e) { - IOException ioe = new IOException("Could not initialize SSL context"); - ioe.initCause(e); - throw ioe; - } catch (NoSuchAlgorithmException e) { - IOException ioe = new IOException("Could not initialize SSL context"); - ioe.initCause(e); - throw ioe; - } - } - } - - /** - * SSL/TLS negotiation. Acquires an SSL socket of a control - * connection and carries out handshake processing. - * @throws IOException A handicap breaks out by sever negotiation. - */ - private void sslNegotiation() throws IOException { - // Evacuation not ssl socket. - planeSocket = _socket_; - - initSslContext(); - - SSLSocketFactory ssf = context.getSocketFactory(); - String ip = _socket_.getInetAddress().getHostAddress(); - int port = _socket_.getPort(); - SSLSocket socket = - (SSLSocket) ssf.createSocket(_socket_, ip, port, true); - socket.setEnableSessionCreation(isCreation); - socket.setUseClientMode(isClientMode); - // server mode - if (!isClientMode) { - socket.setNeedClientAuth(isNeedClientAuth); - socket.setWantClientAuth(isWantClientAuth); - } - if (protocols != null) socket.setEnabledProtocols(protocols); - if (suites != null) socket.setEnabledCipherSuites(suites); - - socket.startHandshake(); - - _socket_ = socket; - _controlInput_ = new BufferedReader(new InputStreamReader( - socket .getInputStream(), getControlEncoding())); - _controlOutput_ = new BufferedWriter(new OutputStreamWriter( - socket.getOutputStream(), getControlEncoding())); - } - - /** - * Get the {@link KeyManager} instance. - * @return The {@link KeyManager} instance - */ - private KeyManager getKeyManager() { - return keyManager; - } - - /** - * Set a {@link KeyManager} to use - * - * @param keyManager The KeyManager implementation to set. - */ - public void setKeyManager(KeyManager keyManager) { - this.keyManager = keyManager; - } - - /** - * Controls whether new a SSL session may be established by this socket. - * @param isCreation The established socket flag. - */ - public void setEnabledSessionCreation(boolean isCreation) { - this.isCreation = isCreation; - } - - /** - * Returns true if new SSL sessions may be established by this socket. - * When a socket does not have a ssl socket, This return False. - * @return true - Indicates that sessions may be created; - * this is the default. - * false - indicates that an existing session must be resumed. - */ - public boolean getEnableSessionCreation() { - if (_socket_ instanceof SSLSocket) - return ((SSLSocket)_socket_).getEnableSessionCreation(); - return false; - } - - /** - * Configures the socket to require client authentication. - * @param isNeedClientAuth The need client auth flag. - */ - public void setNeedClientAuth(boolean isNeedClientAuth) { - this.isNeedClientAuth = isNeedClientAuth; - } - - /** - * Returns true if the socket will require client authentication. - * When a socket does not have a ssl socket, This return False. - * @return true - If the server mode socket should request - * that the client authenticate itself. - */ - public boolean getNeedClientAuth() { - if (_socket_ instanceof SSLSocket) - return ((SSLSocket)_socket_).getNeedClientAuth(); - return false; - } - - /** - * Configures the socket to request client authentication, - * but only if such a request is appropriate to the cipher - * suite negotiated. - * @param isWantClientAuth The want client auth flag. - */ - public void setWantClientAuth(boolean isWantClientAuth) { - this.isWantClientAuth = isWantClientAuth; - } - - /** - * Returns true if the socket will request client authentication. - * When a socket does not have a ssl socket, This return False. - * @return true - If the server mode socket should request - * that the client authenticate itself. - */ - public boolean getWantClientAuth() { - if (_socket_ instanceof SSLSocket) - return ((SSLSocket)_socket_).getWantClientAuth(); - return false; - } - - /** - * Configures the socket to use client (or server) mode in its first - * handshake. - * @param isClientMode The use client mode flag. - */ - public void setUseClientMode(boolean isClientMode) { - this.isClientMode = isClientMode; - } - - /** - * Returns true if the socket is set to use client mode - * in its first handshake. - * When a socket does not have a ssl socket, This return False. - * @return true - If the socket should start its first handshake - * in "client" mode. - */ - public boolean getUseClientMode() { - if (_socket_ instanceof SSLSocket) - return ((SSLSocket)_socket_).getUseClientMode(); - return false; - } - - /** - * Controls which particular cipher suites are enabled for use on this - * connection. I perform setting before a server negotiation. - * @param cipherSuites The cipher suites. - */ - public void setEnabledCipherSuites(String[] cipherSuites) { - suites = new String[cipherSuites.length]; - System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); - } - - /** - * Returns the names of the cipher suites which could be enabled - * for use on this connection. - * When a socket does not have a ssl socket, This return null. - * @return An array of cipher suite names. - */ - public String[] getEnabledCipherSuites() { - if (_socket_ instanceof SSLSocket) - return ((SSLSocket)_socket_).getEnabledCipherSuites(); - return null; - } - - /** - * Controls which particular protocol versions are enabled for use on this - * connection. I perform setting before a server negotiation. - * @param protocolVersions The protocol versions. - */ - public void setEnabledProtocols(String[] protocolVersions) { - protocols = new String[protocolVersions.length]; - System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); - } - - /** - * Returns the names of the protocol versions which are currently - * enabled for use on this connection. - * When a socket does not have a ssl socket, This return null. - * @return An array of protocols. - */ - public String[] getEnabledProtocols() { - if (_socket_ instanceof SSLSocket) - return ((SSLSocket)_socket_).getEnabledProtocols(); - return null; - } - - /** - * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. - * @param pbsz Protection Buffer Size. - * @throws SSLException If it server reply code not equal "200". - * @throws IOException If an I/O error occurs while either sending - * the command. - */ - public void execPBSZ(long pbsz) throws SSLException, IOException { - if (pbsz < 0 || 4294967295L < pbsz) - throw new IllegalArgumentException(); - if (FTPReply.COMMAND_OK != sendCommand( - FTPSCommand._commands[FTPSCommand.PBSZ],String.valueOf(pbsz))) - throw new SSLException(getReplyString()); - } - - /** - * PROT command.
- * C - Clear
- * S - Safe(SSL protocol only)
- * E - Confidential(SSL protocol only)
- * P - Private - * @param prot Data Channel Protection Level. - * @throws SSLException If it server reply code not equal "200". - * @throws IOException If an I/O error occurs while either sending - * the command. - */ - public void execPROT(String prot) throws SSLException, IOException { - if (prot == null) prot = DEFAULT_PROT; - if (!checkPROTValue(prot)) throw new IllegalArgumentException(); - if (FTPReply.COMMAND_OK != sendCommand( - FTPSCommand._commands[FTPSCommand.PROT], prot)) - throw new SSLException(getReplyString()); - if (DEFAULT_PROT.equals(prot)) { - setSocketFactory(null); - setServerSocketFactory(null); - } else { - setSocketFactory(new FTPSSocketFactory(context)); - - initSslContext(); - - SSLServerSocketFactory ssf = context.getServerSocketFactory(); - - setServerSocketFactory(ssf); - } - } - - /** - * I check the value that I can set in PROT Command value. - * @param prot Data Channel Protection Level. - * @return True - A set point is right / False - A set point is not right - */ - private boolean checkPROTValue(String prot) { - for (int p = 0; p < PROT_COMMAND_VALUE.length; p++) { - if (PROT_COMMAND_VALUE[p].equals(prot)) return true; - } - return false; - } - - /** - * I carry out an ftp command. - * When a CCC command was carried out, I steep socket and SocketFactory - * in a state of not ssl. - * @parm command ftp command. - * @return server reply. - * @throws IOException If an I/O error occurs while either sending - * the command. - * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) - */ - @Override - public int sendCommand(String command, String args) throws IOException { - int repCode = super.sendCommand(command, args); - if (FTPSCommand._commands[FTPSCommand.CCC].equals(command)) { - if (FTPReply.COMMAND_OK == repCode) { - // TODO Check this - is this necessary at all? - _socket_ = planeSocket; - setSocketFactory(null); - } else { - throw new SSLException(getReplyString()); - } - } - return repCode; - } - - /** - * Returns a socket of the data connection. - * Wrapped as an {@link SSLSocket}, which carries out handshake processing. - * @pram command The text representation of the FTP command to send. - * @param arg The arguments to the FTP command. - * If this parameter is set to null, then the command is sent with - * no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at any point - * during the establishment and initialization of the connection. - * @throws IOException If there is any problem with the connection. - * @see org.apache.commons.net.ftp.FTPClient#_openDataConnection_(java.lang.String, int) - */ - @Override - protected Socket _openDataConnection_(int command, String arg) - throws IOException { - Socket socket = super._openDataConnection_(command, arg); - if (socket != null && socket instanceof SSLSocket) { - SSLSocket sslSocket = (SSLSocket)socket; - sslSocket.setUseClientMode(isClientMode); - sslSocket.setEnableSessionCreation(isCreation); - // server mode - if (!isClientMode) { - sslSocket.setNeedClientAuth(isNeedClientAuth); - sslSocket.setWantClientAuth(isWantClientAuth); - } - if (suites != null) - sslSocket.setEnabledCipherSuites(suites); - if (protocols != null) - sslSocket.setEnabledProtocols(protocols); - sslSocket.startHandshake(); - } - return socket; - } - - /** - * Get the currently configured {@link TrustManager}. - * - * @return A TrustManager instance. - */ - public TrustManager getTrustManager() { - return trustManager; - } - - /** - * Override the default {@link TrustManager} to use. - * - * @param trustManager The TrustManager implementation to set. - */ - public void setTrustManager(TrustManager trustManager) { - this.trustManager = trustManager; - } - - - -} diff --git a/org/apache/commons/net/ftp/FTPSCommand.java b/org/apache/commons/net/ftp/FTPSCommand.java deleted file mode 100644 index 6fd2efa..0000000 --- a/org/apache/commons/net/ftp/FTPSCommand.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -/** - * I acquire a command added in FTPS. - * @since 2.0 - */ -public final class FTPSCommand { - public static final int AUTH = 0; - public static final int ADAT = 1; - public static final int PBSZ = 2; - public static final int PROT = 3; - public static final int CCC = 4; - - public static final int AUTHENTICATION_SECURITY_MECHANISM = AUTH; - public static final int AUTHENTICATION_SECURITY_DATA = ADAT; - public static final int PROTECTION_BUFFER_SIZE = PBSZ; - public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; - public static final int CLEAR_COMMAND_CHANNEL = CCC; - - static final String[] _commands = {"AUTH","ADAT","PBSZ","PROT","CCC"}; - - /** - * Retrieve the FTPS command string corresponding to a specified - * command code. - *

- * @param command The command code. - * @return The FTPS command string corresponding to a specified - * command code. - */ - public static final String getCommand(int command) { - return _commands[command]; - } -} diff --git a/org/apache/commons/net/ftp/FTPSSocketFactory.java b/org/apache/commons/net/ftp/FTPSSocketFactory.java deleted file mode 100644 index b7e1186..0000000 --- a/org/apache/commons/net/ftp/FTPSSocketFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.net.ftp; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; - - -/** - * - * Implementation of org.apache.commons.net.SocketFactory - * - * @since 2.0 - */ -public class FTPSSocketFactory extends SocketFactory { - - private SSLContext context; - - public FTPSSocketFactory(SSLContext context) { - this.context = context; - } - - @Override - public Socket createSocket(String address, int port) throws UnknownHostException, IOException { - return this.context.getSocketFactory().createSocket(address, port); - } - - @Override - public Socket createSocket(InetAddress address, int port) throws IOException { - return this.context.getSocketFactory().createSocket(address, port); - } - - @Override - public Socket createSocket(String address, int port, InetAddress localAddress, int localPort) throws UnknownHostException, IOException { - return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { - return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); - } - - public ServerSocket createServerSocket(int port) throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port)); - } - - public ServerSocket createServerSocket(int port, int backlog) throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); - } - - public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); - } - - public ServerSocket init(ServerSocket socket) throws IOException { - ((SSLServerSocket) socket).setUseClientMode(true); - return socket; - } -} diff --git a/org/apache/commons/net/ftp/FTPSTrustManager.java b/org/apache/commons/net/ftp/FTPSTrustManager.java deleted file mode 100644 index d1a2dd7..0000000 --- a/org/apache/commons/net/ftp/FTPSTrustManager.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -/** - * Custom {@link TrustManager} implementation. - * - * @version $Id: FTPSTrustManager.java 658520 2008-05-21 01:14:11Z sebb $ - * @since 2.0 - */ -public class FTPSTrustManager implements X509TrustManager -{ - /** - * No-op - */ - public void checkClientTrusted(X509Certificate[] certificates, String authType) - { - return; - } - - public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException - { - for (int i = 0; i < certificates.length; ++i) - { - certificates[i].checkValidity(); - } - } - - public X509Certificate[] getAcceptedIssuers() - { - return null; - } -} diff --git a/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class b/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class deleted file mode 100644 index 0beda53..0000000 Binary files a/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java b/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java deleted file mode 100644 index 4977b3f..0000000 --- a/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPFileEntryParser; -import org.apache.commons.net.ftp.FTPFileEntryParserImpl; - -/** - * This implementation allows to pack some FileEntryParsers together - * and handle the case where to returned dirstyle isnt clearly defined. - * The matching parser will be cached. - * If the cached parser wont match due to the server changed the dirstyle, - * a new matching parser will be searched. - * - * @author Mario Ivankovits - */ -public class CompositeFileEntryParser extends FTPFileEntryParserImpl -{ - private final FTPFileEntryParser[] ftpFileEntryParsers; - private FTPFileEntryParser cachedFtpFileEntryParser; - - public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) - { - super(); - - this.cachedFtpFileEntryParser = null; - this.ftpFileEntryParsers = ftpFileEntryParsers; - } - - public FTPFile parseFTPEntry(String listEntry) - { - if (cachedFtpFileEntryParser != null) - { - FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); - if (matched != null) - { - return matched; - } - } - else - { - for (int iterParser=0; iterParser < ftpFileEntryParsers.length; iterParser++) - { - FTPFileEntryParser ftpFileEntryParser = ftpFileEntryParsers[iterParser]; - - FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); - if (matched != null) - { - cachedFtpFileEntryParser = ftpFileEntryParser; - return matched; - } - } - } - return null; - } -} diff --git a/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class b/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class deleted file mode 100644 index 5cbb5d5..0000000 Binary files a/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java b/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java deleted file mode 100644 index a3e832f..0000000 --- a/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.Calendar; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; - - -/** - *

- * This abstract class implements the common timestamp parsing - * algorithm for all the concrete parsers. Classes derived from - * this one will parse file listings via a supplied regular expression - * that pulls out the date portion as a separate string which is - * passed to the underlying {@link FTPTimestampParser delegate} to - * handle parsing of the file timestamp. - *

- * This class also implements the {@link Configurable Configurable} - * interface to allow the parser to be configured from the outside. - *

- * @since 1.4 - */ -/** - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Style - Code Templates - Comments - */ -public abstract class ConfigurableFTPFileEntryParserImpl -extends RegexFTPFileEntryParserImpl -implements Configurable -{ - - private FTPTimestampParser timestampParser; - - /** - * Only constructor for this absract class. - * @param regex Regular expression used main parsing of the - * file listing. - */ - public ConfigurableFTPFileEntryParserImpl(String regex) - { - super(regex); - this.timestampParser = new FTPTimestampParserImpl(); - } - - /** - * This method is called by the concrete parsers to delegate - * timestamp parsing to the timestamp parser. - *

- * @param timestampStr the timestamp string pulled from the - * file listing by the regular expression parser, to be submitted - * to the timestampParser for extracting the timestamp. - * @return a java.util.Calendar containing results of the - * timestamp parse. - */ - public Calendar parseTimestamp(String timestampStr) throws ParseException { - return this.timestampParser.parseTimestamp(timestampStr); - } - - - /** - * Implementation of the {@link Configurable Configurable} - * interface. Configures this parser by delegating to the - * underlying Configurable FTPTimestampParser implementation, ' - * passing it the supplied {@link FTPClientConfig FTPClientConfig} - * if that is non-null or a default configuration defined by - * each concrete subclass. - *

- * @param config the configuration to be used to configure this parser. - * If it is null, a default configuration defined by - * each concrete subclass is used instead. - */ - public void configure(FTPClientConfig config) - { - if (this.timestampParser instanceof Configurable) { - FTPClientConfig defaultCfg = getDefaultConfiguration(); - if (config != null) { - if (null == config.getDefaultDateFormatStr()) { - config.setDefaultDateFormatStr(defaultCfg.getDefaultDateFormatStr()); - } - if (null == config.getRecentDateFormatStr()) { - config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); - } - ((Configurable)this.timestampParser).configure(config); - } else { - ((Configurable)this.timestampParser).configure(defaultCfg); - } - } - } - - /** - * Each concrete subclass must define this member to create - * a default configuration to be used when that subclass is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for the subclass. - */ - protected abstract FTPClientConfig getDefaultConfiguration(); -} diff --git a/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class b/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class deleted file mode 100644 index a4da6ed..0000000 Binary files a/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java b/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java deleted file mode 100644 index c071a8e..0000000 --- a/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFileEntryParser; - - -/** - * This is the default implementation of the - * FTPFileEntryParserFactory interface. This is the - * implementation that will be used by - * org.apache.commons.net.ftp.FTPClient.listFiles() - * if no other implementation has been specified. - * - * @see org.apache.commons.net.ftp.FTPClient#listFiles - * @see org.apache.commons.net.ftp.FTPClient#setParserFactory - */ -public class DefaultFTPFileEntryParserFactory - implements FTPFileEntryParserFactory -{ - private FTPClientConfig config = null; - - /** - * This default implementation of the FTPFileEntryParserFactory - * interface works according to the following logic: - * First it attempts to interpret the supplied key as a fully - * qualified classname of a class implementing the - * FTPFileEntryParser interface. If that succeeds, a parser - * object of this class is instantiated and is returned; - * otherwise it attempts to interpret the key as an identirier - * commonly used by the FTP SYST command to identify systems. - *

- * If key is not recognized as a fully qualified - * classname known to the system, this method will then attempt - * to see whether it contains a string identifying one of - * the known parsers. This comparison is case-insensitive. - * The intent here is where possible, to select as keys strings - * which are returned by the SYST command on the systems which - * the corresponding parser successfully parses. This enables - * this factory to be used in the auto-detection system. - *

- * - * @param key should be a fully qualified classname corresponding to - * a class implementing the FTPFileEntryParser interface
- * OR
- * a string containing (case-insensitively) one of the - * following keywords: - *

    - *
  • {@link FTPClientConfig#SYST_UNIX UNIX}
  • - *
  • {@link FTPClientConfig#SYST_NT WINDOWS}
  • - *
  • {@link FTPClientConfig#SYST_OS2 OS/2}
  • - *
  • {@link FTPClientConfig#SYST_OS400 OS/400}
  • - *
  • {@link FTPClientConfig#SYST_VMS VMS}
  • - *
  • {@link FTPClientConfig#SYST_MVS MVS}
  • - *
  • {@link FTPClientConfig#SYST_NETWARE}
  • - *
- * @return the FTPFileEntryParser corresponding to the supplied key. - * @throws ParserInitializationException thrown if for any reason the factory cannot resolve - * the supplied key into an FTPFileEntryParser. - * @see FTPFileEntryParser - */ - public FTPFileEntryParser createFileEntryParser(String key) - { - if (key == null) - throw new ParserInitializationException("Parser key cannot be null"); - - Class parserClass = null; - FTPFileEntryParser parser = null; - try - { - parserClass = Class.forName(key); - parser = (FTPFileEntryParser) parserClass.newInstance(); - } - catch (ClassNotFoundException e) - { - try - { - String ukey = null; - if (null != key) - { - ukey = key.toUpperCase(java.util.Locale.ENGLISH); - } - if ((ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) - || (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0)) - { - parser = createUnixFTPEntryParser(); - } - else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) - { - parser = createVMSVersioningFTPEntryParser(); - } - else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) - { - parser = createNTFTPEntryParser(); - } - else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) - { - parser = createOS2FTPEntryParser(); - } - else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 || - ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) - { - parser = createOS400FTPEntryParser(); - } - else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) - { - parser = createMVSEntryParser(); - } - else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) - { - parser = createNetwareFTPEntryParser(); - } - else - { - throw new ParserInitializationException("Unknown parser type: " + key); - } - } - catch (NoClassDefFoundError nf) { - throw new ParserInitializationException("Error initializing parser", nf); - } - - } - catch (NoClassDefFoundError e) - { - throw new ParserInitializationException("Error initializing parser", e); - } - catch (ClassCastException e) - { - throw new ParserInitializationException(parserClass.getName() - + " does not implement the interface " - + "org.apache.commons.net.ftp.FTPFileEntryParser.", e); - } - catch (Throwable e) - { - throw new ParserInitializationException("Error initializing parser", e); - } - - if (parser instanceof Configurable) { - ((Configurable)parser).configure(this.config); - } - return parser; - } - - /** - *

Implementation extracts a key from the supplied - * {@link FTPClientConfig FTPClientConfig} - * parameter and creates an object implementing the - * interface FTPFileEntryParser and uses the supplied configuration - * to configure it. - *

- * Note that this method will generally not be called in scenarios - * that call for autodetection of parser type but rather, for situations - * where the user knows that the server uses a non-default configuration - * and knows what that configuration is. - *

- * @param config A {@link FTPClientConfig FTPClientConfig} - * used to configure the parser created - * - * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. - * @exception ParserInitializationException - * Thrown on any exception in instantiation - * @since 1.4 - */ - public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) - throws ParserInitializationException - { - this.config = config; - String key = config.getServerSystemKey(); - return createFileEntryParser(key); - } - - - public FTPFileEntryParser createUnixFTPEntryParser() - { - return new UnixFTPEntryParser(); - } - - public FTPFileEntryParser createVMSVersioningFTPEntryParser() - { - return new VMSVersioningFTPEntryParser(); - } - - public FTPFileEntryParser createNetwareFTPEntryParser() { - return new NetwareFTPEntryParser(); - } - - public FTPFileEntryParser createNTFTPEntryParser() - { - if (config != null && FTPClientConfig.SYST_NT.equals( - config.getServerSystemKey())) - { - return new NTFTPEntryParser(); - } else { - return new CompositeFileEntryParser(new FTPFileEntryParser[] - { - new NTFTPEntryParser(), - new UnixFTPEntryParser() - }); - } - } - - public FTPFileEntryParser createOS2FTPEntryParser() - { - return new OS2FTPEntryParser(); - } - - public FTPFileEntryParser createOS400FTPEntryParser() - { - if (config != null && - FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) - { - return new OS400FTPEntryParser(); - } else { - return new CompositeFileEntryParser(new FTPFileEntryParser[] - { - new OS400FTPEntryParser(), - new UnixFTPEntryParser() - }); - } - } - - public FTPFileEntryParser createMVSEntryParser() - { - return new MVSFTPEntryParser(); - } - - - -} - diff --git a/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java b/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java deleted file mode 100644 index c7e6da7..0000000 --- a/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.util.Calendar; - -import org.apache.commons.net.ftp.FTPFile; - -/** - * Parser for the Connect Enterprise Unix FTP Server From Sterling Commerce. - * Here is a sample of the sort of output line this parser processes: - * "-C--E-----FTP B QUA1I1 18128 41 Aug 12 13:56 QUADTEST" - *

- * Note: EnterpriseUnixFTPEntryParser can only be instantiated through the - * DefaultFTPParserFactory by classname. It will not be chosen - * by the autodetection scheme. - * - * @version $Id: EnterpriseUnixFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ - * @author Winston Ojeda - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - */ -public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl -{ - - /** - * months abbreviations looked for by this parser. Also used - * to determine which month has been matched by the parser. - */ - private static final String MONTHS = - "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])" - + "([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z]))" - + "(\\S*)\\s*" - + "(\\S+)\\s*" - + "(\\S*)\\s*" - + "(\\d*)\\s*" - + "(\\d*)\\s*" - + MONTHS - + "\\s*" - + "((?:[012]\\d*)|(?:3[01]))\\s*" - + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" - + "(\\S*)(\\s*.*)"; - - /** - * The sole constructor for a EnterpriseUnixFTPEntryParser object. - * - */ - public EnterpriseUnixFTPEntryParser() - { - super(REGEX); - } - - /** - * Parses a line of a unix FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If - * the file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) - { - - FTPFile file = new FTPFile(); - file.setRawListing(entry); - - if (matches(entry)) - { - String usr = group(14); - String grp = group(15); - String filesize = group(16); - String mo = group(17); - String da = group(18); - String yr = group(20); - String hr = group(21); - String min = group(22); - String name = group(23); - - file.setType(FTPFile.FILE_TYPE); - file.setUser(usr); - file.setGroup(grp); - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (NumberFormatException e) - { - // intentionally do nothing - } - - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.MILLISECOND, 0); - cal.set(Calendar.SECOND, - 0); - cal.set(Calendar.MINUTE, - 0); - cal.set(Calendar.HOUR_OF_DAY, - 0); - try - { - - int pos = MONTHS.indexOf(mo); - int month = pos / 4; - if (yr != null) - { - // it's a year - cal.set(Calendar.YEAR, - Integer.parseInt(yr)); - } - else - { - // it must be hour/minute or we wouldn't have matched - int year = cal.get(Calendar.YEAR); - - // if the month we're reading is greater than now, it must - // be last year - if (cal.get(Calendar.MONTH) < month) - { - year--; - } - cal.set(Calendar.YEAR, - year); - cal.set(Calendar.HOUR_OF_DAY, - Integer.parseInt(hr)); - cal.set(Calendar.MINUTE, - Integer.parseInt(min)); - } - cal.set(Calendar.MONTH, - month); - cal.set(Calendar.DATE, - Integer.parseInt(da)); - file.setTimestamp(cal); - } - catch (NumberFormatException e) - { - // do nothing, date will be uninitialized - } - file.setName(name); - - return file; - } - return null; - } -} diff --git a/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class b/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class deleted file mode 100644 index f1bdf1b..0000000 Binary files a/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java b/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java deleted file mode 100644 index e80ec0d..0000000 --- a/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFileEntryParser; - -/** - * The interface describes a factory for creating FTPFileEntryParsers. - * @since 1.2 - */ -public interface FTPFileEntryParserFactory -{ - /** - * Implementation should be a method that decodes the - * supplied key and creates an object implementing the - * interface FTPFileEntryParser. - * - * @param key A string that somehow identifies an - * FTPFileEntryParser to be created. - * - * @return the FTPFileEntryParser created. - * @exception ParserInitializationException - * Thrown on any exception in instantiation - */ - public FTPFileEntryParser createFileEntryParser(String key) - throws ParserInitializationException; - - /** - *

- * Implementation should be a method that extracts - * a key from the supplied {@link FTPClientConfig FTPClientConfig} - * parameter and creates an object implementing the - * interface FTPFileEntryParser and uses the supplied configuration - * to configure it. - *

- * Note that this method will generally not be called in scenarios - * that call for autodetection of parser type but rather, for situations - * where the user knows that the server uses a non-default configuration - * and knows what that configuration is. - *

- * - * @param config A {@link FTPClientConfig FTPClientConfig} - * used to configure the parser created - * - * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. - * @exception ParserInitializationException - * Thrown on any exception in instantiation - * @since 1.4 - */ - public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) - throws ParserInitializationException; - -} diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParser.class b/org/apache/commons/net/ftp/parser/FTPTimestampParser.class deleted file mode 100644 index 32230d8..0000000 Binary files a/org/apache/commons/net/ftp/parser/FTPTimestampParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParser.java b/org/apache/commons/net/ftp/parser/FTPTimestampParser.java deleted file mode 100644 index 40b46cb..0000000 --- a/org/apache/commons/net/ftp/parser/FTPTimestampParser.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.Calendar; - -/** - * This interface specifies the concept of parsing an FTP server's - * timestamp. - * @since 1.4 - */ -public interface FTPTimestampParser { - - /** - * the default default date format. - */ - public static final String DEFAULT_SDF = UnixFTPEntryParser.DEFAULT_DATE_FORMAT; - /** - * the default recent date format. - */ - public static final String DEFAULT_RECENT_SDF = UnixFTPEntryParser.DEFAULT_RECENT_DATE_FORMAT; - - /** - * Parses the supplied datestamp parameter. This parameter typically would - * have been pulled from a longer FTP listing via the regular expression - * mechanism - * @param timestampStr - the timestamp portion of the FTP directory listing - * to be parsed - * @return a java.util.Calendar object initialized to the date - * parsed by the parser - * @throws ParseException if none of the parser mechanisms belonging to - * the implementor can parse the input. - */ - public Calendar parseTimestamp(String timestampStr) throws ParseException; - -} diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class b/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class deleted file mode 100644 index 0ae3067..0000000 Binary files a/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java b/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java deleted file mode 100644 index 02a0cc8..0000000 --- a/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.DateFormatSymbols; -import java.text.ParseException; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; - -/** - * Default implementation of the {@link FTPTimestampParser FTPTimestampParser} - * interface also implements the {@link org.apache.commons.net.ftp.Configurable Configurable} - * interface to allow the parsing to be configured from the outside. - * - * @see ConfigurableFTPFileEntryParserImpl - * @since 1.4 - */ -public class FTPTimestampParserImpl implements - FTPTimestampParser, Configurable -{ - - - private SimpleDateFormat defaultDateFormat; - private SimpleDateFormat recentDateFormat; - private boolean lenientFutureDates = false; - - - /** - * The only constructor for this class. - */ - public FTPTimestampParserImpl() { - setDefaultDateFormat(DEFAULT_SDF); - setRecentDateFormat(DEFAULT_RECENT_SDF); - } - - /** - * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} - * in the {@link FTPTimestampParser FTPTimestampParser} interface - * according to this algorithm: - * - * If the recentDateFormat member has been defined, try to parse the - * supplied string with that. If that parse fails, or if the recentDateFormat - * member has not been defined, attempt to parse with the defaultDateFormat - * member. If that fails, throw a ParseException. - * - * This method allows a {@link Calendar} instance to be passed in which represents the - * current (system) time. - * - * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String) - * - * @param timestampStr The timestamp to be parsed - */ - public Calendar parseTimestamp(String timestampStr) throws ParseException { - Calendar now = Calendar.getInstance(); - return parseTimestamp(timestampStr, now); - } - - /** - * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} - * in the {@link FTPTimestampParser FTPTimestampParser} interface - * according to this algorithm: - * - * If the recentDateFormat member has been defined, try to parse the - * supplied string with that. If that parse fails, or if the recentDateFormat - * member has not been defined, attempt to parse with the defaultDateFormat - * member. If that fails, throw a ParseException. - * - * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String) - * @param timestampStr The timestamp to be parsed - * @param serverTime The current time for the server - * @since 1.5 - */ - public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { - Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it - now.setTimeZone(this.getServerTimeZone()); - Calendar working = (Calendar) now.clone(); - working.setTimeZone(getServerTimeZone()); - ParsePosition pp = new ParsePosition(0); - - Date parsed = null; - if (recentDateFormat != null) { - if (lenientFutureDates) { - // add a day to "now" so that "slop" doesn't cause a date - // slightly in the future to roll back a full year. (Bug 35181) - now.add(Calendar.DATE, 1); - } - parsed = recentDateFormat.parse(timestampStr, pp); - } - if (parsed != null && pp.getIndex() == timestampStr.length()) - { - working.setTime(parsed); - working.set(Calendar.YEAR, now.get(Calendar.YEAR)); - - if (working.after(now)) { - working.add(Calendar.YEAR, -1); - } - } else { - // Temporarily add the current year to the short date time - // to cope with short-date leap year strings. - // e.g. Java's DateFormatter will assume that "Feb 29 12:00" refers to - // Feb 29 1970 (an invalid date) rather than a potentially valid leap year date. - // This is pretty bad hack to work around the deficiencies of the JDK date/time classes. - if (recentDateFormat != null) { - pp = new ParsePosition(0); - int year = now.get(Calendar.YEAR); - String timeStampStrPlusYear = timestampStr + " " + year; - SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy", - recentDateFormat.getDateFormatSymbols()); - hackFormatter.setLenient(false); - hackFormatter.setTimeZone(recentDateFormat.getTimeZone()); - parsed = hackFormatter.parse(timeStampStrPlusYear, pp); - } - if (parsed != null && pp.getIndex() == timestampStr.length() + 5) { - working.setTime(parsed); - } - else { - pp = new ParsePosition(0); - parsed = defaultDateFormat.parse(timestampStr, pp); - // note, length checks are mandatory for us since - // SimpleDateFormat methods will succeed if less than - // full string is matched. They will also accept, - // despite "leniency" setting, a two-digit number as - // a valid year (e.g. 22:04 will parse as 22 A.D.) - // so could mistakenly confuse an hour with a year, - // if we don't insist on full length parsing. - if (parsed != null && pp.getIndex() == timestampStr.length()) { - working.setTime(parsed); - } else { - throw new ParseException( - "Timestamp could not be parsed with older or recent DateFormat", - pp.getIndex()); - } - } - } - return working; - } - - /** - * @return Returns the defaultDateFormat. - */ - public SimpleDateFormat getDefaultDateFormat() { - return defaultDateFormat; - } - /** - * @return Returns the defaultDateFormat pattern string. - */ - public String getDefaultDateFormatString() { - return defaultDateFormat.toPattern(); - } - /** - * @param defaultDateFormat The defaultDateFormat to be set. - */ - private void setDefaultDateFormat(String format) { - if (format != null) { - this.defaultDateFormat = new SimpleDateFormat(format); - this.defaultDateFormat.setLenient(false); - } - } - /** - * @return Returns the recentDateFormat. - */ - public SimpleDateFormat getRecentDateFormat() { - return recentDateFormat; - } - /** - * @return Returns the recentDateFormat. - */ - public String getRecentDateFormatString() { - return recentDateFormat.toPattern(); - } - /** - * @param recentDateFormat The recentDateFormat to set. - */ - private void setRecentDateFormat(String format) { - if (format != null) { - this.recentDateFormat = new SimpleDateFormat(format); - this.recentDateFormat.setLenient(false); - } - } - - /** - * @return returns an array of 12 strings representing the short - * month names used by this parse. - */ - public String[] getShortMonths() { - return defaultDateFormat.getDateFormatSymbols().getShortMonths(); - } - - - /** - * @return Returns the serverTimeZone used by this parser. - */ - public TimeZone getServerTimeZone() { - return this.defaultDateFormat.getTimeZone(); - } - /** - * sets a TimeZone represented by the supplied ID string into all - * of the parsers used by this server. - * @param serverTimeZone Time Id java.util.TimeZone id used by - * the ftp server. If null the client's local time zone is assumed. - */ - private void setServerTimeZone(String serverTimeZoneId) { - TimeZone serverTimeZone = TimeZone.getDefault(); - if (serverTimeZoneId != null) { - serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId); - } - this.defaultDateFormat.setTimeZone(serverTimeZone); - if (this.recentDateFormat != null) { - this.recentDateFormat.setTimeZone(serverTimeZone); - } - } - - /** - * Implementation of the {@link Configurable Configurable} - * interface. Configures this FTPTimestampParser according - * to the following logic: - *

- * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat} - * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat} - * to values supplied in the config based on month names configured as follows: - *

    - *
  • If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString} - * has been supplied in the config, use that to parse parse timestamps.
  • - *
  • Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode} - * has been supplied in the config, use the month names represented - * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language} - * to parse timestamps.
  • - *
  • otherwise use default English month names
  • - *

- * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId} - * has been supplied via the config, set that into all date formats that have - * been configured. - *

- */ - public void configure(FTPClientConfig config) { - DateFormatSymbols dfs = null; - - String languageCode = config.getServerLanguageCode(); - String shortmonths = config.getShortMonthNames(); - if (shortmonths != null) { - dfs = FTPClientConfig.getDateFormatSymbols(shortmonths); - } else if (languageCode != null) { - dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode); - } else { - dfs = FTPClientConfig.lookupDateFormatSymbols("en"); - } - - - String recentFormatString = config.getRecentDateFormatStr(); - if (recentFormatString == null) { - this.recentDateFormat = null; - } else { - this.recentDateFormat = new SimpleDateFormat(recentFormatString, dfs); - this.recentDateFormat.setLenient(false); - } - - String defaultFormatString = config.getDefaultDateFormatStr(); - if (defaultFormatString == null) { - throw new IllegalArgumentException("defaultFormatString cannot be null"); - } - this.defaultDateFormat = new SimpleDateFormat(defaultFormatString, dfs); - this.defaultDateFormat.setLenient(false); - - setServerTimeZone(config.getServerTimeZoneId()); - - this.lenientFutureDates = config.isLenientFutureDates(); - } - /** - * @return Returns the lenientFutureDates. - */ - boolean isLenientFutureDates() { - return lenientFutureDates; - } - /** - * @param lenientFutureDates The lenientFutureDates to set. - */ - void setLenientFutureDates(boolean lenientFutureDates) { - this.lenientFutureDates = lenientFutureDates; - } -} diff --git a/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class b/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class deleted file mode 100644 index 0dc97d0..0000000 Binary files a/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java b/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java deleted file mode 100644 index cd87e6e..0000000 --- a/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.List; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for IBM zOS/MVS - * Systems. - * - * @author Henrik Sorensen - * @author Jeff Nadler - * @author William Noto - * - * @version $Id: MVSFTPEntryParser.java 658520 2008-05-21 01:14:11Z sebb $ - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for - * usage instructions) - */ -public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - static final int UNKNOWN_LIST_TYPE = -1; - static final int FILE_LIST_TYPE = 0; - static final int MEMBER_LIST_TYPE = 1; - static final int UNIX_LIST_TYPE = 2; - static final int JES_LEVEL_1_LIST_TYPE = 3; - static final int JES_LEVEL_2_LIST_TYPE = 4; - - private int isType = UNKNOWN_LIST_TYPE; - - /** - * Fallback parser for Unix-style listings - */ - private UnixFTPEntryParser unixFTPEntryParser; - - /** - * Dates are ignored for file lists, but are used for member lists where - * possible - */ - static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm"; // 2001/09/18 - // 13:52 - - /** - * Matches these entries: Volume Unit Referred Ext Used Recfm Lrecl BlkSz - * Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 80 PS MDI.OKL.WORK - * - */ - static final String FILE_LIST_REGEX = "\\S+\\s+" + // volume - // ignored - "\\S+\\s+" + // unit - ignored - "\\S+\\s+" + // access date - ignored - "\\S+\\s+" + // extents -ignored - "\\S+\\s+" + // used - ignored - "[FV]\\S*\\s+" + // recfm - must start with F or V - "\\S+\\s+" + // logical record length -ignored - "\\S+\\s+" + // block size - ignored - "(PS|PO|PO-E)\\s+" + // Dataset organisation. Many exist - // but only support: PS, PO, PO-E - "(\\S+)\\s*"; // Dataset Name (file name) - - /** - * Matches these entries: Name VV.MM Created Changed Size Init Mod Id - * TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 0 KIL001 - */ - static final String MEMBER_LIST_REGEX = "(\\S+)\\s+" + // name - "\\S+\\s+" + // version, modification (ignored) - "\\S+\\s+" + // create date (ignored) - "(\\S+)\\s+" + // modification date - "(\\S+)\\s+" + // modification time - "\\S+\\s+" + // size in lines (ignored) - "\\S+\\s+" + // size in lines at creation(ignored) - "\\S+\\s+" + // lines modified (ignored) - "\\S+\\s*"; // id of user who modified (ignored) - - /** - * Matches these entries, note: no header: IBMUSER1 JOB01906 OUTPUT 3 Spool - * Files 012345678901234567890123456789012345678901234 1 2 3 4 - */ - static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job - // name - // ignored - "(\\S+)\\s+" + // job number - "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) - "(\\S+)\\s+" + // number of spool files - "(\\S+)\\s+" + // Text "Spool" ignored - "(\\S+)\\s*" // Text "Files" ignored - ; - - /** - * JES INTERFACE LEVEL 2 parser Matches these entries: JOBNAME JOBID OWNER - * STATUS CLASS IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool files - * IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files - * 012345678901234567890123456789012345678901234 1 2 3 4 - * 012345678901234567890123456789012345678901234567890 - */ - - static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job - // name - // ignored - "(\\S+)\\s+" + // job number - "(\\S+)\\s+" + // owner ignored - "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored - "(\\S+)\\s+" + // job class ignored - "(\\S+).*" // rest ignored - ; - - /* - * --------------------------------------------------------------------- - * Very brief and incomplete description of the zOS/MVS-filesystem. (Note: - * "zOS" is the operating system on the mainframe, and is the new name for - * MVS) - * - * The filesystem on the mainframe does not have hierarchal structure as for - * example the unix filesystem. For a more comprehensive description, please - * refer to the IBM manuals - * - * @LINK: - * http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dgt2d440/CONTENTS - * - * - * Dataset names ============= - * - * A dataset name consist of a number of qualifiers separated by '.', each - * qualifier can be at most 8 characters, and the total length of a dataset - * can be max 44 characters including the dots. - * - * - * Dataset organisation ==================== - * - * A dataset represents a piece of storage allocated on one or more disks. - * The structure of the storage is described with the field dataset - * organinsation (DSORG). There are a number of dataset organisations, but - * only two are usable for FTP transfer. - * - * DSORG: PS: sequential, or flat file PO: partitioned dataset PO-E: - * extended partitioned dataset - * - * The PS file is just a flat file, as you would find it on the unix file - * system. - * - * The PO and PO-E files, can be compared to a single level directory - * structure. A PO file consist of a number of dataset members, or files if - * you will. It is possible to CD into the file, and to retrieve the - * individual members. - * - * - * Dataset record format ===================== - * - * The physical layout of the dataset is described on the dataset itself. - * There are a number of record formats (RECFM), but just a few is relavant - * for the FTP transfer. - * - * Any one beginning with either F or V can safely used by FTP transfer. All - * others should only be used with great care, so this version will just - * ignore the other record formats. F means a fixed number of records per - * allocated storage, and V means a variable number of records. - * - * - * Other notes =========== - * - * The file system supports automatically backup and retrieval of datasets. - * If a file is backed up, the ftp LIST command will return: ARCIVE Not - * Direct Access Device KJ.IOP998.ERROR.PL.UNITTEST - * - * - * Implementation notes ==================== - * - * Only datasets that have dsorg PS, PO or PO-E and have recfm beginning - * with F or V, is fully parsed. - * - * The following fields in FTPFile is used: FTPFile.Rawlisting: Always set. - * FTPFile.Type: DIRECTORY_TYPE or FILE_TYPE or UNKNOWN FTPFile.Name: name - * FTPFile.Timestamp: change time or null - * - * - * - * Additional information ====================== - * - * The MVS ftp server supports a number of features via the FTP interface. - * The features are controlled with the FTP command quote site filetype= - * SEQ is the default and used for normal file transfer JES is used to - * interact with the Job Entry Subsystem (JES) similar to a job scheduler - * DB2 is used to interact with a DB2 subsystem - * - * This parser supports SEQ and JES. - * - * - * - * - * - * - */ - - /** - * The sole constructor for a MVSFTPEntryParser object. - * - */ - public MVSFTPEntryParser() { - super(""); // note the regex is set in preParse. - super.configure(null); // configure parser with default configurations - } - - /** - * Parses a line of an z/OS - MVS FTP server file listing and converts it - * into a usable format in the form of an FTPFile instance. - * If the file listing line doesn't describe a file, then - * null is returned. Otherwise a FTPFile - * instance representing the file is returned. - * - * @param entry - * A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) { - boolean isParsed = false; - FTPFile f = new FTPFile(); - - if (isType == FILE_LIST_TYPE) - isParsed = parseFileList(f, entry); - else if (isType == MEMBER_LIST_TYPE) { - isParsed = parseMemberList(f, entry); - if (!isParsed) - isParsed = parseSimpleEntry(f, entry); - } else if (isType == UNIX_LIST_TYPE) { - isParsed = parseUnixList(f, entry); - } else if (isType == JES_LEVEL_1_LIST_TYPE) { - isParsed = parseJeslevel1List(f, entry); - } else if (isType == JES_LEVEL_2_LIST_TYPE) { - isParsed = parseJeslevel2List(f, entry); - } - - if (!isParsed) - f = null; - - return f; - } - - /** - * Parse entries representing a dataset list. Only datasets with DSORG PS or - * PO or PO-E and with RECFM F* or V* will be parsed. - * - * Format of ZOS/MVS file list: 1 2 3 4 5 6 7 8 9 10 Volume Unit Referred - * Ext Used Recfm Lrecl BlkSz Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 - * 80 PS MDI.OKL.WORK ARCIVE Not Direct Access Device - * KJ.IOP998.ERROR.PL.UNITTEST B1N231 3390 2006/03/20 1 15 VB 256 27998 PO - * PLU B1N231 3390 2006/03/20 1 15 VB 256 27998 PO-E PLB - * - * ----------------------------------- Group within Regex [1] Volume [2] - * Unit [3] Referred [4] Ext: number of extents [5] Used [6] Recfm: Record - * format [7] Lrecl: Logical record length [8] BlkSz: Block size [9] Dsorg: - * Dataset organisation. Many exists but only support: PS, PO, PO-E [10] - * Dsname: Dataset name - * - * Note: When volume is ARCIVE, it means the dataset is stored somewhere in - * a tape archive. These entries is currently not supported by this parser. - * A null value is returned. - * - * @param file - * will be updated with Name, Type, Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseFileList(FTPFile file, String entry) { - if (matches(entry)) { - file.setRawListing(entry); - String name = group(2); - String dsorg = group(1); - file.setName(name); - - // DSORG - if ("PS".equals(dsorg)) { - file.setType(FTPFile.FILE_TYPE); - } - else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) { - // regex already ruled out anything other than PO or PO-E - file.setType(FTPFile.DIRECTORY_TYPE); - } - else { - return false; - } - - return true; - } - - return false; - } - - /** - * Parse entries within a partitioned dataset. - * - * Format of a memberlist within a PDS: 1 2 3 4 5 6 7 8 9 Name VV.MM Created - * Changed Size Init Mod Id TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 - * 0 KIL001 TBTOOL 01.12 2002/09/12 2004/11/26 19:54 51 28 0 KIL001 - * - * ------------------------------------------- [1] Name [2] VV.MM: Version . - * modification [3] Created: yyyy / MM / dd [4,5] Changed: yyyy / MM / dd - * HH:mm [6] Size: number of lines [7] Init: number of lines when first - * created [8] Mod: number of modified lines a last save [9] Id: User id for - * last update - * - * - * @param file - * will be updated with Name, Type and Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseMemberList(FTPFile file, String entry) { - if (matches(entry)) { - file.setRawListing(entry); - String name = group(1); - String datestr = group(2) + " " + group(3); - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - try { - file.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - e.printStackTrace(); - // just ignore parsing errors. - // TODO check this is ok - return false; // this is a parsing failure too. - } - return true; - } - - return false; - } - - /** - * Assigns the name to the first word of the entry. Only to be used from a - * safe context, for example from a memberlist, where the regex for some - * reason fails. Then just assign the name field of FTPFile. - * - * @param file - * @param entry - * @return - */ - private boolean parseSimpleEntry(FTPFile file, String entry) { - if (entry != null && entry.length() > 0) { - file.setRawListing(entry); - String name = entry.split(" ")[0]; - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return true; - } - return false; - } - - /** - * Parse the entry as a standard unix file. Using the UnixFTPEntryParser. - * - * @param file - * @param entry - * @return true: entry is parsed, false: entry could not be parsed. - */ - private boolean parseUnixList(FTPFile file, String entry) { - file = unixFTPEntryParser.parseFTPEntry(entry); - if (file == null) - return false; - return true; - } - - /** - * Matches these entries, note: no header: [1] [2] [3] [4] [5] IBMUSER1 - * JOB01906 OUTPUT 3 Spool Files - * 012345678901234567890123456789012345678901234 1 2 3 4 - * ------------------------------------------- Group in regex [1] Job name - * [2] Job number [3] Job status (INPUT,ACTIVE,OUTPUT) [4] Number of sysout - * files [5] The string "Spool Files" - * - * - * @param file - * will be updated with Name, Type and Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseJeslevel1List(FTPFile file, String entry) { - if (matches(entry)) { - if (group(3).equalsIgnoreCase("OUTPUT")) { - file.setRawListing(entry); - String name = group(2); /* Job Number, used by GET */ - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return true; - } - } - - return false; - } - - /** - * Matches these entries, note: no header: [1] [2] [3] [4] [5] JOBNAME JOBID - * OWNER STATUS CLASS IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool - * files IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files - * 012345678901234567890123456789012345678901234 1 2 3 4 - * ------------------------------------------- Group in regex [1] Job name - * [2] Job number [3] Owner [4] Job status (INPUT,ACTIVE,OUTPUT) [5] Job - * Class [6] The rest - * - * - * @param file - * will be updated with Name, Type and Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseJeslevel2List(FTPFile file, String entry) { - if (matches(entry)) { - if (group(4).equalsIgnoreCase("OUTPUT")) { - file.setRawListing(entry); - String name = group(2); /* Job Number, used by GET */ - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return true; - } - } - - return false; - } - - /** - * preParse is called as part of the interface. Per definition is is called - * before the parsing takes place. Three kind of lists is recognize: - * z/OS-MVS File lists z/OS-MVS Member lists unix file lists - * @since 2.0 - */ - @Override - public List preParse(List orig) { - // simply remove the header line. Composite logic will take care of the - // two different types of - // list in short order. - if (orig != null && orig.size() > 0) { - String header = orig.get(0); - if (header.indexOf("Volume") >= 0 && header.indexOf("Dsname") >= 0) { - setType(FILE_LIST_TYPE); - super.setRegex(FILE_LIST_REGEX); - } else if (header.indexOf("Name") >= 0 && header.indexOf("Id") >= 0) { - setType(MEMBER_LIST_TYPE); - super.setRegex(MEMBER_LIST_REGEX); - } else if (header.indexOf("total") == 0) { - setType(UNIX_LIST_TYPE); - unixFTPEntryParser = new UnixFTPEntryParser(); - } else if (header.indexOf("Spool Files") >= 30) { - setType(JES_LEVEL_1_LIST_TYPE); - super.setRegex(JES_LEVEL_1_LIST_REGEX); - } else if (header.indexOf("JOBNAME") == 0 - && header.indexOf("JOBID") > 8) {// header contains JOBNAME JOBID OWNER // STATUS CLASS - setType(JES_LEVEL_2_LIST_TYPE); - super.setRegex(JES_LEVEL_2_LIST_REGEX); - } else { - setType(UNKNOWN_LIST_TYPE); - } - - if (isType != JES_LEVEL_1_LIST_TYPE) { // remove header is necessary - orig.remove(0); - } - } - - return orig; - } - - /** - * Explicitly set the type of listing being processed. - * @param type The listing type. - */ - void setType(int type) { - isType = type; - } - - /* - * @return - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_MVS, - DEFAULT_DATE_FORMAT, null, null, null, null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class b/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class deleted file mode 100644 index bb3ed8f..0000000 Binary files a/org/apache/commons/net/ftp/parser/NTFTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java b/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java deleted file mode 100644 index b6bc75e..0000000 --- a/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for NT Systems. - * - * @author Winston Ojeda - * @author Steve Cohen - * @version $Id: NTFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - private static final String DEFAULT_DATE_FORMAT - = "MM-dd-yy hh:mma"; //11-09-01 12:30PM - - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(\\S+)\\s+(\\S+)\\s+" - + "(?:()|([0-9]+))\\s+" - + "(\\S.*)"; - - /** - * The sole constructor for an NTFTPEntryParser object. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public NTFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of an NTFTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public NTFTPEntryParser(FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an NT FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) - { - FTPFile f = new FTPFile(); - f.setRawListing(entry); - - if (matches(entry)) - { - String datestr = group(1)+" "+group(2); - String dirString = group(3); - String size = group(4); - String name = group(5); - try - { - f.setTimestamp(super.parseTimestamp(datestr)); - } - catch (ParseException e) - { - // intentionally do nothing - } - - if (null == name || name.equals(".") || name.equals("..")) - { - return (null); - } - f.setName(name); - - - if ("

".equals(dirString)) - { - f.setType(FTPFile.DIRECTORY_TYPE); - f.setSize(0); - } - else - { - f.setType(FTPFile.FILE_TYPE); - if (null != size) - { - f.setSize(Long.parseLong(size)); - } - } - return (f); - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - public FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_NT, - DEFAULT_DATE_FORMAT, - null, null, null, null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class b/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class deleted file mode 100644 index 71babc5..0000000 Binary files a/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java b/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java deleted file mode 100644 index 3cbea82..0000000 --- a/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of the proprietary - * extensions for Novell-specific operations are not supported. See - * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html - * for more details. - * - * @author Rory Winston - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @version $Id: NetwareFTPEntryParser.java 658520 2008-05-21 01:14:11Z sebb $ - * @since 1.5 - */ -public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - /** - * Default date format is e.g. Feb 22 2006 - */ - private static final String DEFAULT_DATE_FORMAT = "MMM dd yyyy"; - - /** - * Default recent date format is e.g. Feb 22 17:32 - */ - private static final String DEFAULT_RECENT_DATE_FORMAT = "MMM dd HH:mm"; - - /** - * this is the regular expression used by this parser. - * Example: d [-W---F--] SCION_VOL2 512 Apr 13 23:12 VOL2 - */ - private static final String REGEX = "(d|-){1}\\s+" // Directory/file flag - + "\\[(.*)\\]\\s+" // Attributes - + "(\\S+)\\s+" + "(\\d+)\\s+" // Owner and size - + "(\\S+\\s+\\S+\\s+((\\d+:\\d+)|(\\d{4})))" // Long/short date format - + "\\s+(.*)"; // Filename (incl. spaces) - - /** - * The default constructor for a NetwareFTPEntryParser object. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public NetwareFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of an NetwareFTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public NetwareFTPEntryParser(FTPClientConfig config) { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an NetwareFTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- *

- * Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: - *

    - *
  • S - Supervisor; All rights. - *
  • R - Read; Right to open and read or execute. - *
  • W - Write; Right to open and modify. - *
  • C - Create; Right to create; when assigned to a file, allows a deleted file to be recovered. - *
  • E - Erase; Right to delete. - *
  • M - Modify; Right to rename a file and to change attributes. - *
  • F - File Scan; Right to see directory or file listings. - *
  • A - Access Control; Right to modify trustee assignments and the Inherited Rights Mask. - *
- * - * See here - * for more details - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) { - - FTPFile f = new FTPFile(); - if (matches(entry)) { - String dirString = group(1); - String attrib = group(2); - String user = group(3); - String size = group(4); - String datestr = group(5); - String name = group(9); - - try { - f.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // intentionally do nothing - } - - //is it a DIR or a file - if (dirString.trim().equals("d")) { - f.setType(FTPFile.DIRECTORY_TYPE); - } else // Should be "-" - { - f.setType(FTPFile.FILE_TYPE); - } - - f.setUser(user); - - //set the name - f.setName(name.trim()); - - //set the size - f.setSize(Long.parseLong(size.trim())); - - // Now set the permissions (or at least a subset thereof - full permissions would probably require - // subclassing FTPFile and adding extra metainformation there) - if (attrib.indexOf("R") != -1) { - f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, - true); - } - if (attrib.indexOf("W") != -1) { - f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, - true); - } - - return (f); - } - return null; - - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, - DEFAULT_DATE_FORMAT, DEFAULT_RECENT_DATE_FORMAT, null, null, - null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class b/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class deleted file mode 100644 index 332ae30..0000000 Binary files a/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java b/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java deleted file mode 100644 index dc02ffb..0000000 --- a/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for OS2 Systems. - * - * @author Winston Ojeda - * @author Steve Cohen - * @version $Id: OS2FTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl - -{ - - private static final String DEFAULT_DATE_FORMAT - = "MM-dd-yy HH:mm"; //11-09-01 12:30 - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "\\s*([0-9]+)\\s*" - + "(\\s+|[A-Z]+)\\s*" - + "(DIR|\\s+)\\s*" - + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ - + "(\\S.*)"; - - /** - * The default constructor for a OS2FTPEntryParser object. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public OS2FTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of an OS2FTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public OS2FTPEntryParser(FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an OS2 FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) - { - - FTPFile f = new FTPFile(); - if (matches(entry)) - { - String size = group(1); - String attrib = group(2); - String dirString = group(3); - String datestr = group(4)+" "+group(5); - String name = group(6); - try - { - f.setTimestamp(super.parseTimestamp(datestr)); - } - catch (ParseException e) - { - // intentionally do nothing - } - - - //is it a DIR or a file - if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) - { - f.setType(FTPFile.DIRECTORY_TYPE); - } - else - { - f.setType(FTPFile.FILE_TYPE); - } - - - //set the name - f.setName(name.trim()); - - //set the size - f.setSize(Long.parseLong(size.trim())); - - return (f); - } - return null; - - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_OS2, - DEFAULT_DATE_FORMAT, - null, null, null, null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class b/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class deleted file mode 100644 index b77795b..0000000 Binary files a/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java b/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java deleted file mode 100644 index 66c370b..0000000 --- a/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * @version $Id: OS400FTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ - */ - -public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - private static final String DEFAULT_DATE_FORMAT - = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24 - - - - private static final String REGEX = - "(\\S+)\\s+" // user - + "(\\d+)\\s+" // size - + "(\\S+)\\s+(\\S+)\\s+" // date stuff - + "(\\*\\S+)\\s+" // *STMF/*DIR - + "(\\S+/?)\\s*"; // filename - - - /** - * The default constructor for a OS400FTPEntryParser object. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public OS400FTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of an OS400FTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public OS400FTPEntryParser(FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - - public FTPFile parseFTPEntry(String entry) - { - - FTPFile file = new FTPFile(); - file.setRawListing(entry); - int type; - - if (matches(entry)) - { - String usr = group(1); - String filesize = group(2); - String datestr = group(3)+" "+group(4); - String typeStr = group(5); - String name = group(6); - - try - { - file.setTimestamp(super.parseTimestamp(datestr)); - } - catch (ParseException e) - { - // intentionally do nothing - } - - - if (typeStr.equalsIgnoreCase("*STMF")) - { - type = FTPFile.FILE_TYPE; - } - else if (typeStr.equalsIgnoreCase("*DIR")) - { - type = FTPFile.DIRECTORY_TYPE; - } - else - { - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - file.setUser(usr); - - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (NumberFormatException e) - { - // intentionally do nothing - } - - if (name.endsWith("/")) - { - name = name.substring(0, name.length() - 1); - } - int pos = name.lastIndexOf('/'); - if (pos > -1) - { - name = name.substring(pos + 1); - } - - file.setName(name); - - return file; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_OS400, - DEFAULT_DATE_FORMAT, - null, null, null, null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/ParserInitializationException.class b/org/apache/commons/net/ftp/parser/ParserInitializationException.class deleted file mode 100644 index 4f7fb6f..0000000 Binary files a/org/apache/commons/net/ftp/parser/ParserInitializationException.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/ParserInitializationException.java b/org/apache/commons/net/ftp/parser/ParserInitializationException.java deleted file mode 100644 index 8af9261..0000000 --- a/org/apache/commons/net/ftp/parser/ParserInitializationException.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -/** - * This class encapsulates all errors that may be thrown by - * the process of an FTPFileEntryParserFactory creating and - * instantiating an FTPFileEntryParser. - */ -public class ParserInitializationException extends RuntimeException { - - /** - * Root exception that caused this to be thrown - */ - private final Throwable rootCause; - - /** - * Constucts a ParserInitializationException with just a message - * - * @param message Exception message - */ - public ParserInitializationException(String message) { - super(message); - this.rootCause = null; - } - - /** - * Constucts a ParserInitializationException with a message - * and a root cause. - * - * @param message Exception message - * @param rootCause root cause throwable that caused - * this to be thrown - */ - public ParserInitializationException(String message, Throwable rootCause) { - super(message); - this.rootCause = rootCause; - } - - /** - * returns the root cause of this exception or null - * if no root cause was specified. - * - * @return the root cause of this exception being thrown - */ - public Throwable getRootCause() { - return this.rootCause; - } - -} diff --git a/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class b/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class deleted file mode 100644 index 3cd32f0..0000000 Binary files a/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java b/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java deleted file mode 100644 index 5277444..0000000 --- a/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.net.ftp.parser; - -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.apache.commons.net.ftp.FTPFileEntryParserImpl; - -/** - * This abstract class implements both the older FTPFileListParser and - * newer FTPFileEntryParser interfaces with default functionality. - * All the classes in the parser subpackage inherit from this. - * - * This is the base for all regular based FTPFileEntryParser - * - * @author Steve Cohen - */ -public abstract class RegexFTPFileEntryParserImpl extends - FTPFileEntryParserImpl { - /** - * internal pattern the matcher tries to match, representing a file - * entry - */ - private Pattern pattern = null; - - /** - * internal match result used by the parser - */ - private MatchResult result = null; - - /** - * Internal PatternMatcher object used by the parser. It has protected - * scope in case subclasses want to make use of it for their own purposes. - */ - protected Matcher _matcher_ = null; - - /** - * The constructor for a RegexFTPFileEntryParserImpl object. - * - * @param regex The regular expression with which this object is - * initialized. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen in - * normal conditions. It it is seen, this is a sign that a subclass has - * been created with a bad regular expression. Since the parser must be - * created before use, this means that any bad parser subclasses created - * from this will bomb very quickly, leading to easy detection. - */ - - public RegexFTPFileEntryParserImpl(String regex) { - super(); - setRegex(regex); - } - - /** - * Convenience method delegates to the internal MatchResult's matches() - * method. - * - * @param s the String to be matched - * @return true if s matches this object's regular expression. - */ - - public boolean matches(String s) { - this.result = null; - _matcher_ = pattern.matcher(s); - if (_matcher_.matches()) { - this.result = _matcher_.toMatchResult(); - } - return null != this.result; - } - - /** - * Convenience method - * - * @return the number of groups() in the internal MatchResult. - */ - - public int getGroupCnt() { - if (this.result == null) { - return 0; - } - return this.result.groupCount(); - } - - /** - * Convenience method delegates to the internal MatchResult's group() - * method. - * - * @param matchnum match group number to be retrieved - * - * @return the content of the matchnum'th group of the internal - * match or null if this method is called without a match having - * been made. - */ - public String group(int matchnum) { - if (this.result == null) { - return null; - } - return this.result.group(matchnum); - } - - /** - * For debugging purposes - returns a string shows each match group by - * number. - * - * @return a string shows each match group by number. - */ - - public String getGroupsAsString() { - StringBuffer b = new StringBuffer(); - for (int i = 1; i <= this.result.groupCount(); i++) { - b.append(i).append(") ").append(this.result.group(i)).append( - System.getProperty("line.separator")); - } - return b.toString(); - } - - /** - * Alter the current regular expression being utilised for entry parsing - * and create a new {@link Pattern} instance. - * @param regex The new regular expression - * @return - * @since 2.0 - */ - public boolean setRegex(String regex) { - try { - pattern = Pattern.compile(regex); - } catch (PatternSyntaxException pse) { - throw new IllegalArgumentException("Unparseable regex supplied: " - + regex); - } - return (pattern != null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class b/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class deleted file mode 100644 index 27a082b..0000000 Binary files a/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java b/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java deleted file mode 100644 index 2a2a909..0000000 --- a/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for standard - * Unix Systems. - * - * This class is based on the logic of Daniel Savarese's - * DefaultFTPListParser, but adapted to use regular expressions and to fit the - * new FTPFileEntryParser interface. - * @version $Id: UnixFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - static final String DEFAULT_DATE_FORMAT - = "MMM d yyyy"; //Nov 9 2001 - - static final String DEFAULT_RECENT_DATE_FORMAT - = "MMM d HH:mm"; //Nov 9 20:06 - - static final String NUMERIC_DATE_FORMAT - = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06 - - /** - * Some Linux distributions are now shipping an FTP server which formats - * file listing dates in an all-numeric format: - * "yyyy-MM-dd HH:mm. - * This is a very welcome development, and hopefully it will soon become - * the standard. However, since it is so new, for now, and possibly - * forever, we merely accomodate it, but do not make it the default. - *

- * For now end users may specify this format only via - * UnixFTPEntryParser(FTPClientConfig). - * Steve Cohen - 2005-04-17 - */ - public static final FTPClientConfig NUMERIC_DATE_CONFIG = - new FTPClientConfig( - FTPClientConfig.SYST_UNIX, - NUMERIC_DATE_FORMAT, - null, null, null, null); - - /** - * this is the regular expression used by this parser. - * - * Permissions: - * r the file is readable - * w the file is writable - * x the file is executable - * - the indicated permission is not granted - * L mandatory locking occurs during access (the set-group-ID bit is - * on and the group execution bit is off) - * s the set-user-ID or set-group-ID bit is on, and the corresponding - * user or group execution bit is also on - * S undefined bit-state (the set-user-ID bit is on and the user - * execution bit is off) - * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and - * execution is on - * T the 1000 bit is turned on, and execution is off (undefined bit- - * state) - * e z/OS external link bit - */ - private static final String REGEX = - "([bcdelfmpSs-])" - +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" - + "(\\d+)\\s+" - + "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces) - + "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces) - + "(\\d+(?:,\\s*\\d+)?)\\s+" - - /* - numeric or standard format date - */ - + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+))\\s+" - - /* - year (for non-recent standard format) - or time (for numeric or recent standard format - */ - + "(\\d+(?::\\d+)?)\\s+" - - + "(\\S*)(\\s*.*)"; - - - /** - * The default constructor for a UnixFTPEntryParser object. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public UnixFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public UnixFTPEntryParser(FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - - /** - * Parses a line of a unix (standard) FTP server file listing and converts - * it into a usable format in the form of an FTPFile - * instance. If the file listing line doesn't describe a file, - * null is returned, otherwise a FTPFile - * instance representing the files in the directory is returned. - *

- * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) { - FTPFile file = new FTPFile(); - file.setRawListing(entry); - int type; - boolean isDevice = false; - - if (matches(entry)) - { - String typeStr = group(1); - String hardLinkCount = group(15); - String usr = group(16); - String grp = group(17); - String filesize = group(18); - String datestr = group(19) + " " + group(20); - String name = group(21); - String endtoken = group(22); - - try - { - file.setTimestamp(super.parseTimestamp(datestr)); - } - catch (ParseException e) - { - // intentionally do nothing - } - - - // bcdlfmpSs- - switch (typeStr.charAt(0)) - { - case 'd': - type = FTPFile.DIRECTORY_TYPE; - break; - case 'e': - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'l': - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'b': - case 'c': - isDevice = true; - // break; - fall through - case 'f': - case '-': - type = FTPFile.FILE_TYPE; - break; - default: - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - int g = 4; - for (int access = 0; access < 3; access++, g += 4) - { - // Use != '-' to avoid having to check for suid and sticky bits - file.setPermission(access, FTPFile.READ_PERMISSION, - (!group(g).equals("-"))); - file.setPermission(access, FTPFile.WRITE_PERMISSION, - (!group(g + 1).equals("-"))); - - String execPerm = group(g + 2); - if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) - { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); - } - else - { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); - } - } - - if (!isDevice) - { - try - { - file.setHardLinkCount(Integer.parseInt(hardLinkCount)); - } - catch (NumberFormatException e) - { - // intentionally do nothing - } - } - - file.setUser(usr); - file.setGroup(grp); - - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (NumberFormatException e) - { - // intentionally do nothing - } - - if (null == endtoken) - { - file.setName(name); - } - else - { - // oddball cases like symbolic links, file names - // with spaces in them. - name += endtoken; - if (type == FTPFile.SYMBOLIC_LINK_TYPE) - { - - int end = name.indexOf(" -> "); - // Give up if no link indicator is present - if (end == -1) - { - file.setName(name); - } - else - { - file.setName(name.substring(0, end)); - file.setLink(name.substring(end + 4)); - } - - } - else - { - file.setName(name); - } - } - return file; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_UNIX, - DEFAULT_DATE_FORMAT, - DEFAULT_RECENT_DATE_FORMAT, - null, null, null); - } - -} diff --git a/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class b/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class deleted file mode 100644 index ee8d5f3..0000000 Binary files a/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java b/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java deleted file mode 100644 index 1e55ede..0000000 --- a/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.util.StringTokenizer; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPListParseEngine; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. - * This is a sample of VMS LIST output - * - * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", - * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", - * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", - *

- * Note: VMSFTPEntryParser can only be instantiated through the - * DefaultFTPParserFactory by classname. It will not be chosen - * by the autodetection scheme. - * - *

- * - * @author Winston Ojeda - * @author Steve Cohen - * @author Stephane ESTE-GRACIAS - * @version $Id: VMSFTPEntryParser.java 658518 2008-05-21 01:04:30Z sebb $ - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - */ -public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - private static final String DEFAULT_DATE_FORMAT - = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24 - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(.*;[0-9]+)\\s*" //1 file and version - + "(\\d+)/\\d+\\s*" //2 size/allocated - +"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time - + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner - + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; //9,10,11 Permissions (O,G,W) - // TODO - perhaps restrict permissions to [RWED]* ? - - - - /** - * Constructor for a VMSFTPEntryParser object. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public VMSFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a VMSFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public VMSFTPEntryParser(FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - - - /*** - * Parses an FTP server file listing and converts it into a usable format - * in the form of an array of FTPFile instances. If the - * file list contains no files, null should be - * returned, otherwise an array of FTPFile instances - * representing the files in the directory is returned. - *

- * @param listStream The InputStream from which the file list should be - * read. - * @return The list of file information contained in the given path. null - * if the list could not be obtained or if there are no files in - * the directory. - * @exception IOException If an I/O error occurs reading the listStream. - ***/ - public FTPFile[] parseFileList(InputStream listStream) throws IOException { - FTPListParseEngine engine = new FTPListParseEngine(this); - engine.readServerList(listStream); - return engine.getFiles(); - } - - - - /** - * Parses a line of a VMS FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - public FTPFile parseFTPEntry(String entry) - { - //one block in VMS equals 512 bytes - long longBlock = 512; - - if (matches(entry)) - { - FTPFile f = new FTPFile(); - f.setRawListing(entry); - String name = group(1); - String size = group(2); - String datestr = group(3)+" "+group(4); - String owner = group(5); - String permissions[] = new String[3]; - permissions[0]= group(9); - permissions[1]= group(10); - permissions[2]= group(11); - try - { - f.setTimestamp(super.parseTimestamp(datestr)); - } - catch (ParseException e) - { - // intentionally do nothing - } - - - String grp; - String user; - StringTokenizer t = new StringTokenizer(owner, ","); - switch (t.countTokens()) { - case 1: - grp = null; - user = t.nextToken(); - break; - case 2: - grp = t.nextToken(); - user = t.nextToken(); - break; - default: - grp = null; - user = null; - } - - if (name.lastIndexOf(".DIR") != -1) - { - f.setType(FTPFile.DIRECTORY_TYPE); - } - else - { - f.setType(FTPFile.FILE_TYPE); - } - //set FTPFile name - //Check also for versions to be returned or not - if (isVersioning()) - { - f.setName(name); - } - else - { - name = name.substring(0, name.lastIndexOf(";")); - f.setName(name); - } - //size is retreived in blocks and needs to be put in bytes - //for us humans and added to the FTPFile array - long sizeInBytes = Long.parseLong(size) * longBlock; - f.setSize(sizeInBytes); - - f.setGroup(grp); - f.setUser(user); - //set group and owner - - //Set file permission. - //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain - //R (read) W (write) E (execute) D (delete) - - //iterate for OWNER GROUP WORLD permissions - for (int access = 0; access < 3; access++) - { - String permission = permissions[access]; - - f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); - f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); - f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); - } - - return f; - } - return null; - } - - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. This parser cannot use - * the default implementation of simply calling BufferedReader.readLine(), - * because one entry may span multiple lines. - * - * @param reader The BufferedReader object from which entries are to be - * read. - * - * @return A string representing the next ftp entry or null if none found. - * @exception IOException thrown on any IO Error reading from the reader. - */ - @Override - public String readNextEntry(BufferedReader reader) throws IOException - { - String line = reader.readLine(); - StringBuffer entry = new StringBuffer(); - while (line != null) - { - if (line.startsWith("Directory") || line.startsWith("Total")) { - line = reader.readLine(); - continue; - } - - entry.append(line); - if (line.trim().endsWith(")")) - { - break; - } - line = reader.readLine(); - } - return (entry.length() == 0 ? null : entry.toString()); - } - - protected boolean isVersioning() { - return false; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_VMS, - DEFAULT_DATE_FORMAT, - null, null, null, null); - } - - -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class deleted file mode 100644 index fd27f2a..0000000 Binary files a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser$NameVersion.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class deleted file mode 100644 index c0e20b6..0000000 Binary files a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.class and /dev/null differ diff --git a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java b/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java deleted file mode 100644 index cb25709..0000000 --- a/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.apache.commons.net.ftp.FTPClientConfig; - -/** - * Special implementation VMSFTPEntryParser with versioning turned on. - * This parser removes all duplicates and only leaves the version with the highest - * version number for each filename. - * - * This is a sample of VMS LIST output - * - * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", - * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", - * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", - *

- * - * @author Winston Ojeda - * @author Stephane ESTE-GRACIAS - * @version $Id: VMSVersioningFTPEntryParser.java 636854 2008-03-13 19:55:01Z sebb $ - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser -{ - - private Matcher _preparse_matcher_; - private Pattern _preparse_pattern_; - private static final String PRE_PARSE_REGEX = - "(.*);([0-9]+)\\s*.*"; - - /** - * Constructor for a VMSFTPEntryParser object. Sets the versioning member - * to the supplied value. - * - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public VMSVersioningFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a VMSVersioningFTPEntryParser - * object with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @exception IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public VMSVersioningFTPEntryParser(FTPClientConfig config) - { - super(); - configure(config); - try - { - //_preparse_matcher_ = new Perl5Matcher(); - _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); - } - catch (PatternSyntaxException pse) - { - throw new IllegalArgumentException ( - "Unparseable regex supplied: " + PRE_PARSE_REGEX); - } - - } - - - - private static class NameVersion { - String name; - int versionNumber; - NameVersion(String name, String vers) { - this.name = name; - this.versionNumber = Integer.parseInt(vers); - } - } - - /** - * Implement hook provided for those implementers (such as - * VMSVersioningFTPEntryParser, and possibly others) which return - * multiple files with the same name to remove the duplicates .. - * - * @param original Original list - * - * @return Original list purged of duplicates - */ - @Override - public List preParse(List original) { - original = super.preParse(original); - HashMap existingEntries = new HashMap(); - ListIterator iter = original.listIterator(); - while (iter.hasNext()) { - String entry = iter.next().trim(); - MatchResult result = null; - _preparse_matcher_ = _preparse_pattern_.matcher(entry); - if (_preparse_matcher_.matches()) { - result = _preparse_matcher_.toMatchResult(); - String name = result.group(1); - String version = result.group(2); - NameVersion nv = new NameVersion(name, version); - NameVersion existing = existingEntries.get(name); - if (null != existing) { - if (nv.versionNumber < existing.versionNumber) { - iter.remove(); // removal removes from original list. - continue; - } - } - existingEntries.put(name, nv); - } - - } - // we've now removed all entries less than with less than the largest - // version number for each name that were listed after the largest. - // we now must remove those with smaller than the largest version number - // for each name that were found before the largest - while (iter.hasPrevious()) { - String entry = iter.previous().trim(); - MatchResult result = null; - _preparse_matcher_ = _preparse_pattern_.matcher(entry); - if (_preparse_matcher_.matches()) { - result = _preparse_matcher_.toMatchResult(); - String name = result.group(1); - String version = result.group(2); - NameVersion nv = new NameVersion(name, version); - NameVersion existing = existingEntries.get(name); - if (null != existing) { - if (nv.versionNumber < existing.versionNumber) { - iter.remove(); // removal removes from original list. - } - } - } - - } - return original; - } - - - @Override - protected boolean isVersioning() { - return true; - } - -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/io/CopyStreamAdapter.java b/org/apache/commons/net/io/CopyStreamAdapter.java deleted file mode 100644 index 0679d23..0000000 --- a/org/apache/commons/net/io/CopyStreamAdapter.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.util.EventListener; - -import org.apache.commons.net.util.ListenerList; - -/** - * The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners - * when either of its bytesTransferred() methods are called. Its purpose - * is to facilitate the notification of the progress of a copy operation - * performed by one of the static copyStream() methods in - * org.apache.commons.io.Util to multiple listeners. The static - * copyStream() methods invoke the - * bytesTransfered(long, int) of a CopyStreamListener for performance - * reasons and also because multiple listeners cannot be registered given - * that the methods are static. - *

- *

- * @see CopyStreamEvent - * @see CopyStreamListener - * @see Util - * @author Daniel F. Savarese - * @version $Id: CopyStreamAdapter.java 489397 2006-12-21 16:28:51Z rwinston $ - */ -public class CopyStreamAdapter implements CopyStreamListener -{ - private ListenerList internalListeners; - - /** - * Creates a new copyStreamAdapter. - */ - public CopyStreamAdapter() - { - internalListeners = new ListenerList(); - } - - /** - * This method is invoked by a CopyStreamEvent source after copying - * a block of bytes from a stream. The CopyStreamEvent will contain - * the total number of bytes transferred so far and the number of bytes - * transferred in the last write. The CopyStreamAdapater will relay - * the event to all of its registered listeners, listing itself as the - * source of the event. - * @param event The CopyStreamEvent fired by the copying of a block of - * bytes. - */ - public void bytesTransferred(CopyStreamEvent event) - { - bytesTransferred(event.getTotalBytesTransferred(), - event.getBytesTransferred(), - event.getStreamSize()); - } - - /** - * This method is not part of the JavaBeans model and is used by the - * static methods in the org.apache.commons.io.Util class for efficiency. - * It is invoked after a block of bytes to inform the listener of the - * transfer. The CopyStreamAdapater will create a CopyStreamEvent - * from the arguments and relay the event to all of its registered - * listeners, listing itself as the source of the event. - * @param totalBytesTransferred The total number of bytes transferred - * so far by the copy operation. - * @param bytesTransferred The number of bytes copied by the most recent - * write. - * @param streamSize The number of bytes in the stream being copied. - * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if - * the size is unknown. - */ - public void bytesTransferred(long totalBytesTransferred, - int bytesTransferred, long streamSize) - { - CopyStreamEvent event; - - event = new CopyStreamEvent(this, - totalBytesTransferred, - bytesTransferred, - streamSize); - - for (EventListener listener : internalListeners) - { - ((CopyStreamListener) (listener)).bytesTransferred(event); - } - } - - /** - * Registers a CopyStreamListener to receive CopyStreamEvents. - * Although this method is not declared to be synchronized, it is - * implemented in a thread safe manner. - * @param listener The CopyStreamlistener to register. - */ - public void addCopyStreamListener(CopyStreamListener listener) - { - internalListeners.addListener(listener); - } - - /** - * Unregisters a CopyStreamListener. Although this method is not - * synchronized, it is implemented in a thread safe manner. - * @param listener The CopyStreamlistener to unregister. - */ - public void removeCopyStreamListener(CopyStreamListener listener) - { - internalListeners.removeListener(listener); - } -} diff --git a/org/apache/commons/net/io/CopyStreamEvent.class b/org/apache/commons/net/io/CopyStreamEvent.class deleted file mode 100644 index 66d719c..0000000 Binary files a/org/apache/commons/net/io/CopyStreamEvent.class and /dev/null differ diff --git a/org/apache/commons/net/io/CopyStreamEvent.java b/org/apache/commons/net/io/CopyStreamEvent.java deleted file mode 100644 index d7d0ec3..0000000 --- a/org/apache/commons/net/io/CopyStreamEvent.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.util.EventObject; - -/** - * A CopyStreamEvent is triggered after every write performed by a - * stream copying operation. The event stores the number of bytes - * transferred by the write triggering the event as well as the total - * number of bytes transferred so far by the copy operation. - *

- *

- * @see CopyStreamListener - * @see CopyStreamAdapter - * @see Util - * @author Daniel F. Savarese - * @version $Id: CopyStreamEvent.java 489397 2006-12-21 16:28:51Z rwinston $ - */ -public class CopyStreamEvent extends EventObject -{ - /** - * Constant used to indicate the stream size is unknown. - */ - public static final long UNKNOWN_STREAM_SIZE = -1; - - private int bytesTransferred; - private long totalBytesTransferred; - private long streamSize; - - /** - * Creates a new CopyStreamEvent instance. - * @param source The source of the event. - * @param totalBytesTransferred The total number of bytes transferred so - * far during a copy operation. - * @param bytesTransferred The number of bytes transferred during the - * write that triggered the CopyStreamEvent. - * @param streamSize The number of bytes in the stream being copied. - * This may be set to UNKNOWN_STREAM_SIZE if the - * size is unknown. - */ - public CopyStreamEvent(Object source, long totalBytesTransferred, - int bytesTransferred, long streamSize) - { - super(source); - this.bytesTransferred = bytesTransferred; - this.totalBytesTransferred = totalBytesTransferred; - this.streamSize = streamSize; - } - - /** - * Returns the number of bytes transferred by the write that triggered - * the event. - * @return The number of bytes transferred by the write that triggered - * the vent. - */ - public int getBytesTransferred() - { - return bytesTransferred; - } - - /** - * Returns the total number of bytes transferred so far by the copy - * operation. - * @return The total number of bytes transferred so far by the copy - * operation. - */ - public long getTotalBytesTransferred() - { - return totalBytesTransferred; - } - - /** - * Returns the size of the stream being copied. - * This may be set to UNKNOWN_STREAM_SIZE if the - * size is unknown. - * @return The size of the stream being copied. - */ - public long getStreamSize() - { - return streamSize; - } -} diff --git a/org/apache/commons/net/io/CopyStreamException.class b/org/apache/commons/net/io/CopyStreamException.class deleted file mode 100644 index adf2ebb..0000000 Binary files a/org/apache/commons/net/io/CopyStreamException.class and /dev/null differ diff --git a/org/apache/commons/net/io/CopyStreamException.java b/org/apache/commons/net/io/CopyStreamException.java deleted file mode 100644 index 8d34145..0000000 --- a/org/apache/commons/net/io/CopyStreamException.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; - -/** - * The CopyStreamException class is thrown by the org.apache.commons.io.Util - * copyStream() methods. It stores the number of bytes confirmed to - * have been transferred before an I/O error as well as the IOException - * responsible for the failure of a copy operation. - * @see Util - * @author Daniel F. Savarese - * @version $Id: CopyStreamException.java 489397 2006-12-21 16:28:51Z rwinston $ - */ -public class CopyStreamException extends IOException -{ - private long totalBytesTransferred; - private IOException ioException; - - /** - * Creates a new CopyStreamException instance. - * @param message A message describing the error. - * @param bytesTransferred The total number of bytes transferred before - * an exception was thrown in a copy operation. - * @param exception The IOException thrown during a copy operation. - */ - public CopyStreamException(String message, - long bytesTransferred, - IOException exception) - { - super(message); - totalBytesTransferred = bytesTransferred; - ioException = exception; - } - - /** - * Returns the total number of bytes confirmed to have - * been transferred by a failed copy operation. - * @return The total number of bytes confirmed to have - * been transferred by a failed copy operation. - */ - public long getTotalBytesTransferred() - { - return totalBytesTransferred; - } - - /** - * Returns the IOException responsible for the failure of a copy operation. - * @return The IOException responsible for the failure of a copy operation. - */ - public IOException getIOException() - { - return ioException; - } -} diff --git a/org/apache/commons/net/io/CopyStreamListener.class b/org/apache/commons/net/io/CopyStreamListener.class deleted file mode 100644 index 3d5bb08..0000000 Binary files a/org/apache/commons/net/io/CopyStreamListener.class and /dev/null differ diff --git a/org/apache/commons/net/io/CopyStreamListener.java b/org/apache/commons/net/io/CopyStreamListener.java deleted file mode 100644 index 9e97fb9..0000000 --- a/org/apache/commons/net/io/CopyStreamListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.util.EventListener; - -/** - * The CopyStreamListener class can accept CopyStreamEvents to keep track - * of the progress of a stream copying operation. However, it is currently - * not used that way within NetComponents for performance reasons. Rather - * the bytesTransferred(long, int) method is called directly rather than - * passing an event to bytesTransferred(CopyStreamEvent), saving the creation - * of a CopyStreamEvent instance. Also, the only place where - * CopyStreamListener is currently used within NetComponents is in the - * static methods of the uninstantiable org.apache.commons.io.Util class, which - * would preclude the use of addCopyStreamListener and - * removeCopyStreamListener methods. However, future additions may use the - * JavaBean event model, which is why the hooks have been included from the - * beginning. - *

- *

- * @see CopyStreamEvent - * @see CopyStreamAdapter - * @see Util - * @author Daniel F. Savarese - * @version $Id: CopyStreamListener.java 489397 2006-12-21 16:28:51Z rwinston $ - */ -public interface CopyStreamListener extends EventListener -{ - /** - * This method is invoked by a CopyStreamEvent source after copying - * a block of bytes from a stream. The CopyStreamEvent will contain - * the total number of bytes transferred so far and the number of bytes - * transferred in the last write. - * @param event The CopyStreamEvent fired by the copying of a block of - * bytes. - */ - public void bytesTransferred(CopyStreamEvent event); - - - /** - * This method is not part of the JavaBeans model and is used by the - * static methods in the org.apache.commons.io.Util class for efficiency. - * It is invoked after a block of bytes to inform the listener of the - * transfer. - * @param totalBytesTransferred The total number of bytes transferred - * so far by the copy operation. - * @param bytesTransferred The number of bytes copied by the most recent - * write. - * @param streamSize The number of bytes in the stream being copied. - * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if - * the size is unknown. - */ - public void bytesTransferred(long totalBytesTransferred, - int bytesTransferred, - long streamSize); -} diff --git a/org/apache/commons/net/io/DotTerminatedMessageReader.java b/org/apache/commons/net/io/DotTerminatedMessageReader.java deleted file mode 100644 index c0f344d..0000000 --- a/org/apache/commons/net/io/DotTerminatedMessageReader.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; -import java.io.PushbackReader; -import java.io.Reader; - -/** - * DotTerminatedMessageReader is a class used to read messages from a - * server that are terminated by a single dot followed by a - * <CR><LF> - * sequence and with double dots appearing at the begining of lines which - * do not signal end of message yet start with a dot. Various Internet - * protocols such as NNTP and POP3 produce messages of this type. - *

- * This class handles stripping of the duplicate period at the beginning - * of lines starting with a period, converts NETASCII newlines to the - * local line separator format, truncates the end of message indicator, - * and ensures you cannot read past the end of the message. - * @author Daniel F. Savarese - * @version $Id: DotTerminatedMessageReader.java 636825 2008-03-13 18:34:52Z sebb $ - */ -public final class DotTerminatedMessageReader extends Reader -{ - private static final String LS; - private static final char[] LS_CHARS; - - static - { - LS = System.getProperty("line.separator"); - LS_CHARS = LS.toCharArray(); - } - - private boolean atBeginning; - private boolean eof; - private int pos; - private char[] internalBuffer; - private PushbackReader internalReader; - - /** - * Creates a DotTerminatedMessageReader that wraps an existing Reader - * input source. - * @param reader The Reader input source containing the message. - */ - public DotTerminatedMessageReader(Reader reader) - { - super(reader); - internalBuffer = new char[LS_CHARS.length + 3]; - pos = internalBuffer.length; - // Assumes input is at start of message - atBeginning = true; - eof = false; - internalReader = new PushbackReader(reader); - } - - /** - * Reads and returns the next character in the message. If the end of the - * message has been reached, returns -1. Note that a call to this method - * may result in multiple reads from the underlying input stream to decode - * the message properly (removing doubled dots and so on). All of - * this is transparent to the programmer and is only mentioned for - * completeness. - * @return The next character in the message. Returns -1 if the end of the - * message has been reached. - * @exception IOException If an error occurs while reading the underlying - * stream. - */ - @Override - public int read() throws IOException - { - int ch; - - synchronized (lock) - { - if (pos < internalBuffer.length) - { - return internalBuffer[pos++]; - } - - if (eof) - { - return -1; - } - - if ((ch = internalReader.read()) == -1) - { - eof = true; - return -1; - } - - if (atBeginning) - { - atBeginning = false; - if (ch == '.') - { - ch = internalReader.read(); - - if (ch != '.') - { - // read newline - eof = true; - internalReader.read(); - return -1; - } - else - { - return '.'; - } - } - } - - if (ch == '\r') - { - ch = internalReader.read(); - - if (ch == '\n') - { - ch = internalReader.read(); - - if (ch == '.') - { - ch = internalReader.read(); - - if (ch != '.') - { - // read newline and indicate end of file - internalReader.read(); - eof = true; - } - else - { - internalBuffer[--pos] = (char) ch; - } - } - else - { - internalReader.unread(ch); - } - - pos -= LS_CHARS.length; - System.arraycopy(LS_CHARS, 0, internalBuffer, pos, - LS_CHARS.length); - ch = internalBuffer[pos++]; - } - else - { - internalBuffer[--pos] = (char) ch; - return '\r'; - } - } - - return ch; - } - } - - /** - * Reads the next characters from the message into an array and - * returns the number of characters read. Returns -1 if the end of the - * message has been reached. - * @param buffer The character array in which to store the characters. - * @return The number of characters read. Returns -1 if the - * end of the message has been reached. - * @exception IOException If an error occurs in reading the underlying - * stream. - */ - @Override - public int read(char[] buffer) throws IOException - { - return read(buffer, 0, buffer.length); - } - - /** - * Reads the next characters from the message into an array and - * returns the number of characters read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * @param buffer The character array in which to store the characters. - * @param offset The offset into the array at which to start storing - * characters. - * @param length The number of characters to read. - * @return The number of characters read. Returns -1 if the - * end of the message has been reached. - * @exception IOException If an error occurs in reading the underlying - * stream. - */ - @Override - public int read(char[] buffer, int offset, int length) throws IOException - { - int ch, off; - synchronized (lock) - { - if (length < 1) - { - return 0; - } - if ((ch = read()) == -1) - { - return -1; - } - off = offset; - - do - { - buffer[offset++] = (char) ch; - } - while (--length > 0 && (ch = read()) != -1); - - return (offset - off); - } - } - - /** - * Determines if the message is ready to be read. - * @return True if the message is ready to be read, false if not. - * @exception IOException If an error occurs while checking the underlying - * stream. - */ - @Override - public boolean ready() throws IOException - { - synchronized (lock) - { - return (pos < internalBuffer.length || internalReader.ready()); - } - } - - /** - * Closes the message for reading. This doesn't actually close the - * underlying stream. The underlying stream may still be used for - * communicating with the server and therefore is not closed. - *

- * If the end of the message has not yet been reached, this method - * will read the remainder of the message until it reaches the end, - * so that the underlying stream may continue to be used properly - * for communicating with the server. If you do not fully read - * a message, you MUST close it, otherwise your program will likely - * hang or behave improperly. - * @exception IOException If an error occurs while reading the - * underlying stream. - */ - @Override - public void close() throws IOException - { - synchronized (lock) - { - if (internalReader == null) - { - return; - } - - if (!eof) - { - while (read() != -1) - { - ; - } - } - eof = true; - atBeginning = false; - pos = internalBuffer.length; - internalReader = null; - } - } -} diff --git a/org/apache/commons/net/io/DotTerminatedMessageWriter.java b/org/apache/commons/net/io/DotTerminatedMessageWriter.java deleted file mode 100644 index 853e42f..0000000 --- a/org/apache/commons/net/io/DotTerminatedMessageWriter.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; -import java.io.Writer; - -/*** - * DotTerminatedMessageWriter is a class used to write messages to a - * server that are terminated by a single dot followed by a - * <CR><LF> - * sequence and with double dots appearing at the begining of lines which - * do not signal end of message yet start with a dot. Various Internet - * protocols such as NNTP and POP3 produce messages of this type. - *

- * This class handles the doubling of line-starting periods, - * converts single linefeeds to NETASCII newlines, and on closing - * will send the final message terminator dot and NETASCII newline - * sequence. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class DotTerminatedMessageWriter extends Writer -{ - private static final int __NOTHING_SPECIAL_STATE = 0; - private static final int __LAST_WAS_CR_STATE = 1; - private static final int __LAST_WAS_NL_STATE = 2; - - private int __state; - private Writer __output; - - - /*** - * Creates a DotTerminatedMessageWriter that wraps an existing Writer - * output destination. - *

- * @param output The Writer output destination to write the message. - ***/ - public DotTerminatedMessageWriter(Writer output) - { - super(output); - __output = output; - __state = __NOTHING_SPECIAL_STATE; - } - - - /*** - * Writes a character to the output. Note that a call to this method - * may result in multiple writes to the underling Writer in order to - * convert naked linefeeds to NETASCII line separators and to double - * line-leading periods. This is transparent to the programmer and - * is only mentioned for completeness. - *

- * @param ch The character to write. - * @exception IOException If an error occurs while writing to the - * underlying output. - ***/ - @Override - public void write(int ch) throws IOException - { - synchronized (lock) - { - switch (ch) - { - case '\r': - __state = __LAST_WAS_CR_STATE; - __output.write('\r'); - return ; - case '\n': - if (__state != __LAST_WAS_CR_STATE) - __output.write('\r'); - __output.write('\n'); - __state = __LAST_WAS_NL_STATE; - return ; - case '.': - // Double the dot at the beginning of a line - if (__state == __LAST_WAS_NL_STATE) - __output.write('.'); - // Fall through - default: - __state = __NOTHING_SPECIAL_STATE; - __output.write(ch); - return ; - } - } - } - - - /*** - * Writes a number of characters from a character array to the output - * starting from a given offset. - *

- * @param buffer The character array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of characters to write. - * @exception IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override - public void write(char[] buffer, int offset, int length) throws IOException - { - synchronized (lock) - { - while (length-- > 0) - write(buffer[offset++]); - } - } - - - /*** - * Writes a character array to the output. - *

- * @param buffer The character array to write. - * @exception IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override - public void write(char[] buffer) throws IOException - { - write(buffer, 0, buffer.length); - } - - - /*** - * Writes a String to the output. - *

- * @param string The String to write. - * @exception IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override - public void write(String string) throws IOException - { - write(string.toCharArray()); - } - - - /*** - * Writes part of a String to the output starting from a given offset. - *

- * @param string The String to write. - * @param offset The offset into the String at which to start copying data. - * @param length The number of characters to write. - * @exception IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override - public void write(String string, int offset, int length) throws IOException - { - write(string.toCharArray(), offset, length); - } - - - /*** - * Flushes the underlying output, writing all buffered output. - *

- * @exception IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override - public void flush() throws IOException - { - synchronized (lock) - { - __output.flush(); - } - } - - - /*** - * Flushes the underlying output, writing all buffered output, but doesn't - * actually close the underlying stream. The underlying stream may still - * be used for communicating with the server and therefore is not closed. - *

- * @exception IOException If an error occurs while writing to the underlying - * output or closing the Writer. - ***/ - @Override - public void close() throws IOException - { - synchronized (lock) - { - if (__output == null) - return ; - - if (__state == __LAST_WAS_CR_STATE) - __output.write('\n'); - else if (__state != __LAST_WAS_NL_STATE) - __output.write("\r\n"); - - __output.write(".\r\n"); - - __output.flush(); - __output = null; - } - } - -} diff --git a/org/apache/commons/net/io/FromNetASCIIInputStream.class b/org/apache/commons/net/io/FromNetASCIIInputStream.class deleted file mode 100644 index d3bf9c1..0000000 Binary files a/org/apache/commons/net/io/FromNetASCIIInputStream.class and /dev/null differ diff --git a/org/apache/commons/net/io/FromNetASCIIInputStream.java b/org/apache/commons/net/io/FromNetASCIIInputStream.java deleted file mode 100644 index 76588ab..0000000 --- a/org/apache/commons/net/io/FromNetASCIIInputStream.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; - -/*** - * This class wraps an input stream, replacing all occurrences - * of <CR><LF> (carriage return followed by a linefeed), - * which is the NETASCII standard for representing a newline, with the - * local line separator representation. You would use this class to - * implement ASCII file transfers requiring conversion from NETASCII. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class FromNetASCIIInputStream extends PushbackInputStream -{ - static final boolean _noConversionRequired; - static final String _lineSeparator; - static final byte[] _lineSeparatorBytes; - - static { - _lineSeparator = System.getProperty("line.separator"); - _noConversionRequired = _lineSeparator.equals("\r\n"); - _lineSeparatorBytes = _lineSeparator.getBytes(); - } - - private int __length = 0; - - /*** - * Returns true if the NetASCII line separator differs from the system - * line separator, false if they are the same. This method is useful - * to determine whether or not you need to instantiate a - * FromNetASCIIInputStream object. - *

- * @return True if the NETASCII line separator differs from the local - * system line separator, false if they are the same. - ***/ - public static final boolean isConversionRequired() - { - return !_noConversionRequired; - } - - /*** - * Creates a FromNetASCIIInputStream instance that wraps an existing - * InputStream. - ***/ - public FromNetASCIIInputStream(InputStream input) - { - super(input, _lineSeparatorBytes.length + 1); - } - - - private int __read() throws IOException - { - int ch; - - ch = super.read(); - - if (ch == '\r') - { - ch = super.read(); - if (ch == '\n') - { - unread(_lineSeparatorBytes); - ch = super.read(); - // This is a kluge for read(byte[], ...) to read the right amount - --__length; - } - else - { - if (ch != -1) - unread(ch); - return '\r'; - } - } - - return ch; - } - - - /*** - * Reads and returns the next byte in the stream. If the end of the - * message has been reached, returns -1. Note that a call to this method - * may result in multiple reads from the underlying input stream in order - * to convert NETASCII line separators to the local line separator format. - * This is transparent to the programmer and is only mentioned for - * completeness. - *

- * @return The next character in the stream. Returns -1 if the end of the - * stream has been reached. - * @exception IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override - public int read() throws IOException - { - if (_noConversionRequired) - return super.read(); - - return __read(); - } - - - /*** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - *

- * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @exception IOException If an error occurs in reading the underlying - * stream. - ***/ - @Override - public int read(byte buffer[]) throws IOException - { - return read(buffer, 0, buffer.length); - } - - - /*** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - *

- * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @exception IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override - public int read(byte buffer[], int offset, int length) throws IOException - { - int ch, off; - - if (length < 1) - return 0; - - ch = available(); - - __length = (length > ch ? ch : length); - - // If nothing is available, block to read only one character - if (__length < 1) - __length = 1; - - if (_noConversionRequired) - return super.read(buffer, offset, __length); - - if ((ch = __read()) == -1) - return -1; - - off = offset; - - do - { - buffer[offset++] = (byte)ch; - } - while (--__length > 0 && (ch = __read()) != -1); - - - return (offset - off); - } - - - // PushbackInputStream in JDK 1.1.3 returns the wrong thing - /*** - * Returns the number of bytes that can be read without blocking EXCEPT - * when newline conversions have to be made somewhere within the - * available block of bytes. In other words, you really should not - * rely on the value returned by this method if you are trying to avoid - * blocking. - ***/ - @Override - public int available() throws IOException - { - return (buf.length - pos) + in.available(); - } - -} diff --git a/org/apache/commons/net/io/FromNetASCIIOutputStream.java b/org/apache/commons/net/io/FromNetASCIIOutputStream.java deleted file mode 100644 index c025a1b..0000000 --- a/org/apache/commons/net/io/FromNetASCIIOutputStream.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/*** - * This class wraps an output stream, replacing all occurrences - * of <CR><LF> (carriage return followed by a linefeed), - * which is the NETASCII standard for representing a newline, with the - * local line separator representation. You would use this class to - * implement ASCII file transfers requiring conversion from NETASCII. - *

- * Because of the translation process, a call to flush() will - * not flush the last byte written if that byte was a carriage - * return. A call to {@link #close close() }, however, will - * flush the carriage return. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class FromNetASCIIOutputStream extends FilterOutputStream -{ - private boolean __lastWasCR; - - /*** - * Creates a FromNetASCIIOutputStream instance that wraps an existing - * OutputStream. - *

- * @param output The OutputStream to wrap. - ***/ - public FromNetASCIIOutputStream(OutputStream output) - { - super(output); - __lastWasCR = false; - } - - - private void __write(int ch) throws IOException - { - switch (ch) - { - case '\r': - __lastWasCR = true; - // Don't write anything. We need to see if next one is linefeed - break; - case '\n': - if (__lastWasCR) - { - out.write(FromNetASCIIInputStream._lineSeparatorBytes); - __lastWasCR = false; - break; - } - __lastWasCR = false; - out.write('\n'); - break; - default: - if (__lastWasCR) - { - out.write('\r'); - __lastWasCR = false; - } - out.write(ch); - break; - } - } - - - /*** - * Writes a byte to the stream. Note that a call to this method - * might not actually write a byte to the underlying stream until a - * subsequent character is written, from which it can be determined if - * a NETASCII line separator was encountered. - * This is transparent to the programmer and is only mentioned for - * completeness. - *

- * @param ch The byte to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public synchronized void write(int ch) - throws IOException - { - if (FromNetASCIIInputStream._noConversionRequired) - { - out.write(ch); - return ; - } - - __write(ch); - } - - - /*** - * Writes a byte array to the stream. - *

- * @param buffer The byte array to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public synchronized void write(byte buffer[]) - throws IOException - { - write(buffer, 0, buffer.length); - } - - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - *

- * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public synchronized void write(byte buffer[], int offset, int length) - throws IOException - { - if (FromNetASCIIInputStream._noConversionRequired) - { - // FilterOutputStream method is very slow. - //super.write(buffer, offset, length); - out.write(buffer, offset, length); - return ; - } - - while (length-- > 0) - __write(buffer[offset++]); - } - - - /*** - * Closes the stream, writing all pending data. - *

- * @exception IOException If an error occurs while closing the stream. - ***/ - @Override - public synchronized void close() - throws IOException - { - if (FromNetASCIIInputStream._noConversionRequired) - { - super.close(); - return ; - } - - if (__lastWasCR) - out.write('\r'); - super.close(); - } -} diff --git a/org/apache/commons/net/io/SocketInputStream.class b/org/apache/commons/net/io/SocketInputStream.class deleted file mode 100644 index 97657e8..0000000 Binary files a/org/apache/commons/net/io/SocketInputStream.class and /dev/null differ diff --git a/org/apache/commons/net/io/SocketInputStream.java b/org/apache/commons/net/io/SocketInputStream.java deleted file mode 100644 index 673f434..0000000 --- a/org/apache/commons/net/io/SocketInputStream.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.Socket; - -/*** - * This class wraps an input stream, storing a reference to its originating - * socket. When the stream is closed, it will also close the socket - * immediately afterward. This class is useful for situations where you - * are dealing with a stream originating from a socket, but do not have - * a reference to the socket, and want to make sure it closes when the - * stream closes. - *

- *

- * @author Daniel F. Savarese - * @see SocketOutputStream - ***/ - -public class SocketInputStream extends FilterInputStream -{ - private Socket __socket; - - /*** - * Creates a SocketInputStream instance wrapping an input stream and - * storing a reference to a socket that should be closed on closing - * the stream. - *

- * @param socket The socket to close on closing the stream. - * @param stream The input stream to wrap. - ***/ - public SocketInputStream(Socket socket, InputStream stream) - { - super(stream); - __socket = socket; - } - - /*** - * Closes the stream and immediately afterward closes the referenced - * socket. - *

- * @exception IOException If there is an error in closing the stream - * or socket. - ***/ - @Override - public void close() throws IOException - { - super.close(); - __socket.close(); - } -} diff --git a/org/apache/commons/net/io/SocketOutputStream.class b/org/apache/commons/net/io/SocketOutputStream.class deleted file mode 100644 index 41a30e5..0000000 Binary files a/org/apache/commons/net/io/SocketOutputStream.class and /dev/null differ diff --git a/org/apache/commons/net/io/SocketOutputStream.java b/org/apache/commons/net/io/SocketOutputStream.java deleted file mode 100644 index abd7f5d..0000000 --- a/org/apache/commons/net/io/SocketOutputStream.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.Socket; - -/*** - * This class wraps an output stream, storing a reference to its originating - * socket. When the stream is closed, it will also close the socket - * immediately afterward. This class is useful for situations where you - * are dealing with a stream originating from a socket, but do not have - * a reference to the socket, and want to make sure it closes when the - * stream closes. - *

- *

- * @author Daniel F. Savarese - * @see SocketInputStream - ***/ - -public class SocketOutputStream extends FilterOutputStream -{ - private Socket __socket; - - /*** - * Creates a SocketOutputStream instance wrapping an output stream and - * storing a reference to a socket that should be closed on closing - * the stream. - *

- * @param socket The socket to close on closing the stream. - * @param stream The input stream to wrap. - ***/ - public SocketOutputStream(Socket socket, OutputStream stream) - { - super(stream); - __socket = socket; - } - - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. This method bypasses the equivalent method in - * FilterOutputStream because the FilterOutputStream implementation is - * very inefficient. - *

- * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public void write(byte buffer[], int offset, int length) throws IOException - { - out.write(buffer, offset, length); - } - - - /*** - * Closes the stream and immediately afterward closes the referenced - * socket. - *

- * @exception IOException If there is an error in closing the stream - * or socket. - ***/ - @Override - public void close() throws IOException - { - super.close(); - __socket.close(); - } -} diff --git a/org/apache/commons/net/io/ToNetASCIIInputStream.java b/org/apache/commons/net/io/ToNetASCIIInputStream.java deleted file mode 100644 index 55e4735..0000000 --- a/org/apache/commons/net/io/ToNetASCIIInputStream.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/*** - * This class wraps an input stream, replacing all singly occurring - * <LF> (linefeed) characters with <CR><LF> (carriage return - * followed by linefeed), which is the NETASCII standard for representing - * a newline. - * You would use this class to implement ASCII file transfers requiring - * conversion to NETASCII. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class ToNetASCIIInputStream extends FilterInputStream -{ - private static final int __NOTHING_SPECIAL = 0; - private static final int __LAST_WAS_CR = 1; - private static final int __LAST_WAS_NL = 2; - private int __status; - - /*** - * Creates a ToNetASCIIInputStream instance that wraps an existing - * InputStream. - *

- * @param input The InputStream to . - ***/ - public ToNetASCIIInputStream(InputStream input) - { - super(input); - __status = __NOTHING_SPECIAL; - } - - - /*** - * Reads and returns the next byte in the stream. If the end of the - * message has been reached, returns -1. - *

- * @return The next character in the stream. Returns -1 if the end of the - * stream has been reached. - * @exception IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override - public int read() throws IOException - { - int ch; - - if (__status == __LAST_WAS_NL) - { - __status = __NOTHING_SPECIAL; - return '\n'; - } - - ch = in.read(); - - switch (ch) - { - case '\r': - __status = __LAST_WAS_CR; - return '\r'; - case '\n': - if (__status != __LAST_WAS_CR) - { - __status = __LAST_WAS_NL; - return '\r'; - } - // else fall through - default: - __status = __NOTHING_SPECIAL; - return ch; - } - // statement not reached - //return ch; - } - - - /*** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - *

- * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @exception IOException If an error occurs in reading the underlying - * stream. - ***/ - @Override - public int read(byte buffer[]) throws IOException - { - return read(buffer, 0, buffer.length); - } - - - /*** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - *

- * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @exception IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override - public int read(byte buffer[], int offset, int length) throws IOException - { - int ch, off; - - if (length < 1) - return 0; - - ch = available(); - - if (length > ch) - length = ch; - - // If nothing is available, block to read only one character - if (length < 1) - length = 1; - - if ((ch = read()) == -1) - return -1; - - off = offset; - - do - { - buffer[offset++] = (byte)ch; - } - while (--length > 0 && (ch = read()) != -1); - - return (offset - off); - } - - /*** Returns false. Mark is not supported. ***/ - @Override - public boolean markSupported() - { - return false; - } - - @Override - public int available() throws IOException - { - int result; - - result = in.available(); - - if (__status == __LAST_WAS_NL) - return (result + 1); - - return result; - } -} diff --git a/org/apache/commons/net/io/ToNetASCIIOutputStream.class b/org/apache/commons/net/io/ToNetASCIIOutputStream.class deleted file mode 100644 index 62185e4..0000000 Binary files a/org/apache/commons/net/io/ToNetASCIIOutputStream.class and /dev/null differ diff --git a/org/apache/commons/net/io/ToNetASCIIOutputStream.java b/org/apache/commons/net/io/ToNetASCIIOutputStream.java deleted file mode 100644 index aeacc98..0000000 --- a/org/apache/commons/net/io/ToNetASCIIOutputStream.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/*** - * This class wraps an output stream, replacing all singly occurring - * <LF> (linefeed) characters with <CR><LF> (carriage return - * followed by linefeed), which is the NETASCII standard for representing - * a newline. - * You would use this class to implement ASCII file transfers requiring - * conversion to NETASCII. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class ToNetASCIIOutputStream extends FilterOutputStream -{ - private boolean __lastWasCR; - - /*** - * Creates a ToNetASCIIOutputStream instance that wraps an existing - * OutputStream. - *

- * @param output The OutputStream to wrap. - ***/ - public ToNetASCIIOutputStream(OutputStream output) - { - super(output); - __lastWasCR = false; - } - - - /*** - * Writes a byte to the stream. Note that a call to this method - * may result in multiple writes to the underlying input stream in order - * to convert naked newlines to NETASCII line separators. - * This is transparent to the programmer and is only mentioned for - * completeness. - *

- * @param ch The byte to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public synchronized void write(int ch) - throws IOException - { - switch (ch) - { - case '\r': - __lastWasCR = true; - out.write('\r'); - return ; - case '\n': - if (!__lastWasCR) - out.write('\r'); - // Fall through - default: - __lastWasCR = false; - out.write(ch); - return ; - } - } - - - /*** - * Writes a byte array to the stream. - *

- * @param buffer The byte array to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public synchronized void write(byte buffer[]) - throws IOException - { - write(buffer, 0, buffer.length); - } - - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - *

- * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public synchronized void write(byte buffer[], int offset, int length) - throws IOException - { - while (length-- > 0) - write(buffer[offset++]); - } - -} diff --git a/org/apache/commons/net/io/Util.class b/org/apache/commons/net/io/Util.class deleted file mode 100644 index 7509801..0000000 Binary files a/org/apache/commons/net/io/Util.class and /dev/null differ diff --git a/org/apache/commons/net/io/Util.java b/org/apache/commons/net/io/Util.java deleted file mode 100644 index 4e85a93..0000000 --- a/org/apache/commons/net/io/Util.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; - -/*** - * The Util class cannot be instantiated and stores short static convenience - * methods that are often quite useful. - *

- *

- * @see CopyStreamException - * @see CopyStreamListener - * @see CopyStreamAdapter - * @author Daniel F. Savarese - ***/ - -public final class Util -{ - /*** - * The default buffer size used by {@link #copyStream copyStream } - * and {@link #copyReader copyReader }. It's value is 1024. - ***/ - public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; - - // Cannot be instantiated - private Util() - { } - - - /*** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - *

- * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * @param streamSize The number of bytes in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @param flush Whether to flush the output stream after every - * write. This is necessary for interactive sessions that rely on - * buffered streams. If you don't flush, the data will stay in - * the stream buffer. - * @exception CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyStream(InputStream source, OutputStream dest, - int bufferSize, long streamSize, - CopyStreamListener listener, - boolean flush) - throws CopyStreamException - { - int bytes; - long total; - byte[] buffer; - - buffer = new byte[bufferSize]; - total = 0; - - try - { - while ((bytes = source.read(buffer)) != -1) - { - // Technically, some read(byte[]) methods may return 0 and we cannot - // accept that as an indication of EOF. - - if (bytes == 0) - { - bytes = source.read(); - if (bytes < 0) - break; - dest.write(bytes); - if(flush) - dest.flush(); - ++total; - if (listener != null) - listener.bytesTransferred(total, 1, streamSize); - continue; - } - - dest.write(buffer, 0, bytes); - if(flush) - dest.flush(); - total += bytes; - if (listener != null) - listener.bytesTransferred(total, bytes, streamSize); - } - } - catch (IOException e) - { - throw new CopyStreamException("IOException caught while copying.", - total, e); - } - - return total; - } - - - /*** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - *

- * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * @param streamSize The number of bytes in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @exception CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyStream(InputStream source, OutputStream dest, - int bufferSize, long streamSize, - CopyStreamListener listener) - throws CopyStreamException - { - return copyStream(source, dest, bufferSize, streamSize, listener, - true); - } - - - /*** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size. The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - *

- * @param source The source InputStream. - * @param dest The destination OutputStream. - * @return The number of bytes read/written in the copy operation. - * @exception CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyStream(InputStream source, OutputStream dest, - int bufferSize) - throws CopyStreamException - { - return copyStream(source, dest, bufferSize, - CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); - } - - - /*** - * Same as copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); - ***/ - public static final long copyStream(InputStream source, OutputStream dest) - throws CopyStreamException - { - return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); - } - - - /*** - * Copies the contents of a Reader to a Writer using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the Reader are - * read until its end is reached, but neither the source nor the - * destination are closed. You must do this yourself outside of the - * method call. The number of characters read/written is returned. - *

- * @param source The source Reader. - * @param dest The destination writer. - * @param bufferSize The number of characters to buffer during the copy. - * @param streamSize The number of characters in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @return The number of characters read/written in the copy operation. - * @exception CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyReader(Reader source, Writer dest, - int bufferSize, long streamSize, - CopyStreamListener listener) - throws CopyStreamException - { - int chars; - long total; - char[] buffer; - - buffer = new char[bufferSize]; - total = 0; - - try - { - while ((chars = source.read(buffer)) != -1) - { - // Technically, some read(char[]) methods may return 0 and we cannot - // accept that as an indication of EOF. - if (chars == 0) - { - chars = source.read(); - if (chars < 0) - break; - dest.write(chars); - dest.flush(); - ++total; - if (listener != null) - listener.bytesTransferred(total, chars, streamSize); - continue; - } - - dest.write(buffer, 0, chars); - dest.flush(); - total += chars; - if (listener != null) - listener.bytesTransferred(total, chars, streamSize); - } - } - catch (IOException e) - { - throw new CopyStreamException("IOException caught while copying.", - total, e); - } - - return total; - } - - - /*** - * Copies the contents of a Reader to a Writer using a - * copy buffer of a given size. The contents of the Reader are - * read until its end is reached, but neither the source nor the - * destination are closed. You must do this yourself outside of the - * method call. The number of characters read/written is returned. - *

- * @param source The source Reader. - * @param dest The destination writer. - * @param bufferSize The number of characters to buffer during the copy. - * @return The number of characters read/written in the copy operation. - * @exception CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyReader(Reader source, Writer dest, - int bufferSize) - throws CopyStreamException - { - return copyReader(source, dest, bufferSize, - CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); - } - - - /*** - * Same as copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); - ***/ - public static final long copyReader(Reader source, Writer dest) - throws CopyStreamException - { - return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); - } - -} diff --git a/org/apache/commons/net/nntp/Article.java b/org/apache/commons/net/nntp/Article.java deleted file mode 100644 index cccba3b..0000000 --- a/org/apache/commons/net/nntp/Article.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -import java.util.ArrayList; -import java.util.StringTokenizer; - -/** - * This is a class that contains the basic state needed for message retrieval and threading. - * With thanks to Jamie Zawinski - * @author rwinston - * - */ -public class Article implements Threadable { - private int articleNumber; - private String subject; - private String date; - private String articleId; - private String simplifiedSubject; - private String from; - private StringBuffer header; - private StringBuffer references; - private boolean isReply = false; - - public Article kid, next; - - public Article() { - header = new StringBuffer(); - } - - /** - * Adds an arbitrary header key and value to this message's header. - * @param name the header name - * @param val the header value - */ - public void addHeaderField(String name, String val) { - header.append(name); - header.append(": "); - header.append(val); - header.append('\n'); - } - - /** - * Adds a message-id to the list of messages that this message references (i.e. replies to) - * @param msgId - */ - public void addReference(String msgId) { - if (references == null) { - references = new StringBuffer(); - references.append("References: "); - } - references.append(msgId); - references.append("\t"); - } - - /** - * Returns the MessageId references as an array of Strings - * @return an array of message-ids - */ - public String[] getReferences() { - if (references == null) - return new String[0]; - ArrayList list = new ArrayList(); - int terminator = references.toString().indexOf(':'); - StringTokenizer st = - new StringTokenizer(references.substring(terminator), "\t"); - while (st.hasMoreTokens()) { - list.add(st.nextToken()); - } - return list.toArray(new String[list.size()]); - } - - /** - * Attempts to parse the subject line for some typical reply signatures, and strip them out - * - */ - private void simplifySubject() { - int start = 0; - String subject = getSubject(); - int len = subject.length(); - - boolean done = false; - - while (!done) { - done = true; - - // skip whitespace - // "Re: " breaks this - while (start < len && subject.charAt(start) == ' ') { - start++; - } - - if (start < (len - 2) - && (subject.charAt(start) == 'r' || subject.charAt(start) == 'R') - && (subject.charAt(start + 1) == 'e' || subject.charAt(start + 1) == 'E')) { - - if (subject.charAt(start + 2) == ':') { - start += 3; // Skip "Re:" - isReply = true; - done = false; - } else if ( - start < (len - 2) - && - (subject.charAt(start + 2) == '[' || subject.charAt(start + 2) == '(')) { - - int i = start + 3; - - while (i < len && subject.charAt(i) >= '0' && subject.charAt(i) <= '9') - i++; - - if (i < (len - 1) - && (subject.charAt(i) == ']' || subject.charAt(i) == ')') - && subject.charAt(i + 1) == ':') { - start = i + 2; - isReply = true; - done = false; - } - } - } - - if (simplifiedSubject == "(no subject)") - simplifiedSubject = ""; - - int end = len; - - while (end > start && subject.charAt(end - 1) < ' ') - end--; - - if (start == 0 && end == len) - simplifiedSubject = subject; - else - simplifiedSubject = subject.substring(start, end); - } - } - - /** - * Recursive method that traverses a pre-threaded graph (or tree) - * of connected Article objects and prints them out. - * @param article the root of the article 'tree' - * @param depth the current tree depth - */ - public static void printThread(Article article, int depth) { - for (int i = 0; i < depth; ++i) - System.out.print("==>"); - System.out.println(article.getSubject() + "\t" + article.getFrom()); - if (article.kid != null) - printThread(article.kid, depth + 1); - if (article.next != null) - printThread(article.next, depth); - } - - public String getArticleId() { - return articleId; - } - - public int getArticleNumber() { - return articleNumber; - } - - public String getDate() { - return date; - } - - public String getFrom() { - return from; - } - - public String getSubject() { - return subject; - } - - public void setArticleId(String string) { - articleId = string; - } - - public void setArticleNumber(int i) { - articleNumber = i; - } - - public void setDate(String string) { - date = string; - } - - public void setFrom(String string) { - from = string; - } - - public void setSubject(String string) { - subject = string; - } - - - public boolean isDummy() { - return (getSubject() == null); - } - - public String messageThreadId() { - return articleId; - } - - public String[] messageThreadReferences() { - return getReferences(); - } - - public String simplifiedSubject() { - if(simplifiedSubject == null) - simplifySubject(); - return simplifiedSubject; - } - - - public boolean subjectIsReply() { - if(simplifiedSubject == null) - simplifySubject(); - return isReply; - } - - - public void setChild(Threadable child) { - this.kid = (Article) child; - flushSubjectCache(); - } - - private void flushSubjectCache() { - simplifiedSubject = null; - } - - - public void setNext(Threadable next) { - this.next = (Article)next; - flushSubjectCache(); - } - - - public Threadable makeDummy() { - return new Article(); - } -} diff --git a/org/apache/commons/net/nntp/ArticlePointer.java b/org/apache/commons/net/nntp/ArticlePointer.java deleted file mode 100644 index a810cad..0000000 --- a/org/apache/commons/net/nntp/ArticlePointer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -/** - * This class is a structure used to return article number and unique - * id information extracted from an NNTP server reply. You will normally - * want this information when issuing a STAT command, implemented by - * {@link NNTPClient#selectArticle selectArticle}. - * @author Daniel F. Savarese - * @see NNTPClient - */ -public final class ArticlePointer -{ - /** The number of the referenced article. */ - public int articleNumber; - /** - * The unique id of the referenced article, including the enclosing - * < and > symbols which are technically not part of the - * identifier, but are required by all NNTP commands taking an - * article id as an argument. - */ - public String articleId; -} diff --git a/org/apache/commons/net/nntp/NNTP.java b/org/apache/commons/net/nntp/NNTP.java deleted file mode 100644 index 225e064..0000000 --- a/org/apache/commons/net/nntp/NNTP.java +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandListener; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; - -/*** - * The NNTP class is not meant to be used by itself and is provided - * only so that you may easily implement your own NNTP client if - * you so desire. If you have no need to perform your own implementation, - * you should use {@link org.apache.commons.net.nntp.NNTPClient}. - * The NNTP class is made public to provide access to various NNTP constants - * and to make it easier for adventurous programmers (or those with special - * needs) to interact with the NNTP protocol and implement their own clients. - * A set of methods with names corresponding to the NNTP command names are - * provided to facilitate this interaction. - *

- * You should keep in mind that the NNTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period or if the server is being shutdown by the operator or - * some other reason. The NNTP class will detect a - * premature NNTP server connection closing when it receives a - * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } - * response to a command. - * When that occurs, the NNTP class method encountering that reply will throw - * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} - * . - * NNTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by NNTP. Before disconnecting, you may check the - * last reply code and text with - * {@link #getReplyCode getReplyCode } and - * {@link #getReplyString getReplyString }. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @author Rory Winston - * @author Ted Wise - * @see NNTPClient - * @see NNTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - ***/ - -public class NNTP extends SocketClient -{ - /*** The default NNTP port. Its value is 119 according to RFC 977. ***/ - public static final int DEFAULT_PORT = 119; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - private static final String __DEFAULT_ENCODING = "ISO-8859-1"; - - private StringBuffer __commandBuffer; - - boolean _isAllowedToPost; - int _replyCode; - String _replyString; - - /** - * Wraps {@link SocketClient#_input_} - * to communicate with server. Initialized by {@link #_connectAction_}. - * All server reads should be done through this variable. - */ - protected BufferedReader _reader_; - - /** - * Wraps {@link SocketClient#_output_} - * to communicate with server. Initialized by {@link #_connectAction_}. - * All server reads should be done through this variable. - */ - protected BufferedWriter _writer_; - - /*** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and te firing of ProtocolCommandEvents. - ***/ - protected ProtocolCommandSupport _commandSupport_; - - /*** - * The default NNTP constructor. Sets the default port to - * DEFAULT_PORT and initializes internal data structures - * for saving NNTP reply information. - ***/ - public NNTP() - { - setDefaultPort(DEFAULT_PORT); - __commandBuffer = new StringBuffer(); - _replyString = null; - _reader_ = null; - _writer_ = null; - _isAllowedToPost = false; - _commandSupport_ = new ProtocolCommandSupport(this); - } - - private void __getReply() throws IOException - { - _replyString = _reader_.readLine(); - - if (_replyString == null) - throw new NNTPConnectionClosedException( - "Connection closed without indication."); - - // In case we run into an anomaly we don't want fatal index exceptions - // to be thrown. - if (_replyString.length() < 3) - throw new MalformedServerReplyException( - "Truncated server reply: " + _replyString); - try - { - _replyCode = Integer.parseInt(_replyString.substring(0, 3)); - } - catch (NumberFormatException e) - { - throw new MalformedServerReplyException( - "Could not parse response code.\nServer Reply: " + _replyString); - } - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireReplyReceived(_replyCode, _replyString + - SocketClient.NETASCII_EOL); - - if (_replyCode == NNTPReply.SERVICE_DISCONTINUED) - throw new NNTPConnectionClosedException( - "NNTP response 400 received. Server closed connection."); - } - - /*** - * Initiates control connections and gets initial reply, determining - * if the client is allowed to post to the server. Initializes - * {@link #_reader_} and {@link #_writer_} to wrap - * {@link SocketClient#_input_} and {@link SocketClient#_output_}. - ***/ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - _reader_ = - new BufferedReader(new InputStreamReader(_input_, - __DEFAULT_ENCODING)); - _writer_ = - new BufferedWriter(new OutputStreamWriter(_output_, - __DEFAULT_ENCODING)); - __getReply(); - - _isAllowedToPost = (_replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED); - } - - /*** - * Adds a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to add. - ***/ - public void addProtocolCommandListener(ProtocolCommandListener listener) - { - _commandSupport_.addProtocolCommandListener(listener); - } - - /*** - * Removes a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to remove. - ***/ - public void removeProtocolCommandListener(ProtocolCommandListener listener) - { - _commandSupport_.removeProtocolCommandListener(listener); - } - - /*** - * Closes the connection to the NNTP server and sets to null - * some internal data so that the memory may be reclaimed by the - * garbage collector. The reply text and code information from the - * last command is voided so that the memory it used may be reclaimed. - *

- * @exception IOException If an error occurs while disconnecting. - ***/ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - _reader_ = null; - _writer_ = null; - _replyString = null; - _isAllowedToPost = false; - } - - - /*** - * Indicates whether or not the client is allowed to post articles to - * the server it is currently connected to. - *

- * @return True if the client can post articles to the server, false - * otherwise. - ***/ - public boolean isAllowedToPost() - { - return _isAllowedToPost; - } - - - /*** - * Sends an NNTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString }. - *

- * @param command The text representation of the NNTP command to send. - * @param args The arguments to the NNTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the NNTP reply code returned by the server - * in response to the command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command, String args) throws IOException - { - String message; - - __commandBuffer.setLength(0); - __commandBuffer.append(command); - - if (args != null) - { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - - _writer_.write(message = __commandBuffer.toString()); - _writer_.flush(); - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireCommandSent(command, message); - - __getReply(); - return _replyCode; - } - - - /*** - * Sends an NNTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString }. - *

- * @param command The NNTPCommand constant corresponding to the NNTP command - * to send. - * @param args The arguments to the NNTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the NNTP reply code returned by the server - * in response to the command. - * in response to the command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command, String args) throws IOException - { - return sendCommand(NNTPCommand._commands[command], args); - } - - - /*** - * Sends an NNTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString }. - *

- * @param command The text representation of the NNTP command to send. - * @return The integer value of the NNTP reply code returned by the server - * in response to the command. - * in response to the command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command) throws IOException - { - return sendCommand(command, null); - } - - - /*** - * Sends an NNTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString }. - *

- * @param command The NNTPCommand constant corresponding to the NNTP command - * to send. - * @return The integer value of the NNTP reply code returned by the server - * in response to the command. - * in response to the command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command) throws IOException - { - return sendCommand(command, null); - } - - - /*** - * Returns the integer value of the reply code of the last NNTP reply. - * You will usually only use this method after you connect to the - * NNTP server to check that the connection was successful since - * connect is of type void. - *

- * @return The integer value of the reply code of the last NNTP reply. - ***/ - public int getReplyCode() - { - return _replyCode; - } - - /*** - * Fetches a reply from the NNTP server and returns the integer reply - * code. After calling this method, the actual reply text can be accessed - * from {@link #getReplyString getReplyString }. Only use this - * method if you are implementing your own NNTP client or if you need to - * fetch a secondary response from the NNTP server. - *

- * @return The integer value of the reply code of the fetched NNTP reply. - * in response to the command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while - * receiving the server reply. - ***/ - public int getReply() throws IOException - { - __getReply(); - return _replyCode; - } - - - /*** - * Returns the entire text of the last NNTP server response exactly - * as it was received, not including the end of line marker. - *

- * @return The entire text from the last NNTP response as a String. - ***/ - public String getReplyString() - { - return _replyString; - } - - - /*** - * A convenience method to send the NNTP ARTICLE command to the server, - * receive the initial reply, and return the reply code. - *

- * @param messageId The message identifier of the requested article, - * including the encapsulating < and > characters. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int article(String messageId) throws IOException - { - return sendCommand(NNTPCommand.ARTICLE, messageId); - } - - /*** - * A convenience method to send the NNTP ARTICLE command to the server, - * receive the initial reply, and return the reply code. - *

- * @param articleNumber The number of the article to request from the - * currently selected newsgroup. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int article(int articleNumber) throws IOException - { - return sendCommand(NNTPCommand.ARTICLE, Integer.toString(articleNumber)); - } - - /*** - * A convenience method to send the NNTP ARTICLE command to the server, - * receive the initial reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int article() throws IOException - { - return sendCommand(NNTPCommand.ARTICLE); - } - - - - /*** - * A convenience method to send the NNTP BODY command to the server, - * receive the initial reply, and return the reply code. - *

- * @param messageId The message identifier of the requested article, - * including the encapsulating < and > characters. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int body(String messageId) throws IOException - { - return sendCommand(NNTPCommand.BODY, messageId); - } - - /*** - * A convenience method to send the NNTP BODY command to the server, - * receive the initial reply, and return the reply code. - *

- * @param articleNumber The number of the article to request from the - * currently selected newsgroup. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int body(int articleNumber) throws IOException - { - return sendCommand(NNTPCommand.BODY, Integer.toString(articleNumber)); - } - - /*** - * A convenience method to send the NNTP BODY command to the server, - * receive the initial reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int body() throws IOException - { - return sendCommand(NNTPCommand.BODY); - } - - - - /*** - * A convenience method to send the NNTP HEAD command to the server, - * receive the initial reply, and return the reply code. - *

- * @param messageId The message identifier of the requested article, - * including the encapsulating < and > characters. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int head(String messageId) throws IOException - { - return sendCommand(NNTPCommand.HEAD, messageId); - } - - /*** - * A convenience method to send the NNTP HEAD command to the server, - * receive the initial reply, and return the reply code. - *

- * @param articleNumber The number of the article to request from the - * currently selected newsgroup. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int head(int articleNumber) throws IOException - { - return sendCommand(NNTPCommand.HEAD, Integer.toString(articleNumber)); - } - - /*** - * A convenience method to send the NNTP HEAD command to the server, - * receive the initial reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int head() throws IOException - { - return sendCommand(NNTPCommand.HEAD); - } - - - - /*** - * A convenience method to send the NNTP STAT command to the server, - * receive the initial reply, and return the reply code. - *

- * @param messageId The message identifier of the requested article, - * including the encapsulating < and > characters. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat(String messageId) throws IOException - { - return sendCommand(NNTPCommand.STAT, messageId); - } - - /*** - * A convenience method to send the NNTP STAT command to the server, - * receive the initial reply, and return the reply code. - *

- * @param articleNumber The number of the article to request from the - * currently selected newsgroup. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat(int articleNumber) throws IOException - { - return sendCommand(NNTPCommand.STAT, Integer.toString(articleNumber)); - } - - /*** - * A convenience method to send the NNTP STAT command to the server, - * receive the initial reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat() throws IOException - { - return sendCommand(NNTPCommand.STAT); - } - - - /*** - * A convenience method to send the NNTP GROUP command to the server, - * receive the reply, and return the reply code. - *

- * @param newsgroup The name of the newsgroup to select. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int group(String newsgroup) throws IOException - { - return sendCommand(NNTPCommand.GROUP, newsgroup); - } - - - /*** - * A convenience method to send the NNTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help() throws IOException - { - return sendCommand(NNTPCommand.HELP); - } - - - /*** - * A convenience method to send the NNTP IHAVE command to the server, - * receive the reply, and return the reply code. - *

- * @param messageId The article identifier, - * including the encapsulating < and > characters. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int ihave(String messageId) throws IOException - { - return sendCommand(NNTPCommand.IHAVE, messageId); - } - - - /*** - * A convenience method to send the NNTP LAST command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int last() throws IOException - { - return sendCommand(NNTPCommand.LAST); - } - - - - /*** - * A convenience method to send the NNTP LIST command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int list() throws IOException - { - return sendCommand(NNTPCommand.LIST); - } - - - - /*** - * A convenience method to send the NNTP NEXT command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int next() throws IOException - { - return sendCommand(NNTPCommand.NEXT); - } - - - /*** - * A convenience method to send the NNTP NEWGROUPS command to the server, - * receive the reply, and return the reply code. - *

- * @param date The date after which to check for new groups. - * Date format is YYMMDD - * @param time The time after which to check for new groups. - * Time format is HHMMSS using a 24-hour clock. - * @param GMT True if the time is in GMT, false if local server time. - * @param distributions Comma-separated distribution list to check for - * new groups. Set to null if no distributions. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int newgroups(String date, String time, boolean GMT, - String distributions) throws IOException - { - StringBuffer buffer = new StringBuffer(); - - buffer.append(date); - buffer.append(' '); - buffer.append(time); - - if (GMT) - { - buffer.append(' '); - buffer.append("GMT"); - } - - if (distributions != null) - { - buffer.append(" <"); - buffer.append(distributions); - buffer.append('>'); - } - - return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString()); - } - - - /*** - * A convenience method to send the NNTP NEWGROUPS command to the server, - * receive the reply, and return the reply code. - *

- * @param newsgroups A comma-separated list of newsgroups to check for new - * news. - * @param date The date after which to check for new news. - * Date format is YYMMDD - * @param time The time after which to check for new news. - * Time format is HHMMSS using a 24-hour clock. - * @param GMT True if the time is in GMT, false if local server time. - * @param distributions Comma-separated distribution list to check for - * new news. Set to null if no distributions. - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int newnews(String newsgroups, String date, String time, boolean GMT, - String distributions) throws IOException - { - StringBuffer buffer = new StringBuffer(); - - buffer.append(newsgroups); - buffer.append(' '); - buffer.append(date); - buffer.append(' '); - buffer.append(time); - - if (GMT) - { - buffer.append(' '); - buffer.append("GMT"); - } - - if (distributions != null) - { - buffer.append(" <"); - buffer.append(distributions); - buffer.append('>'); - } - - return sendCommand(NNTPCommand.NEWNEWS, buffer.toString()); - } - - - - /*** - * A convenience method to send the NNTP POST command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int post() throws IOException - { - return sendCommand(NNTPCommand.POST); - } - - - - /*** - * A convenience method to send the NNTP QUIT command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int quit() throws IOException - { - return sendCommand(NNTPCommand.QUIT); - } - - /*** - * A convenience method to send the AUTHINFO USER command to the server, - * receive the reply, and return the reply code. (See RFC 2980) - *

- * @param username A valid username. - * @return The reply code received from the server. The server should - * return a 381 or 281 for this command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int authinfoUser(String username) throws IOException { - String userParameter = "USER " + username; - return sendCommand(NNTPCommand.AUTHINFO, userParameter); - } - - /*** - * A convenience method to send the AUTHINFO PASS command to the server, - * receive the reply, and return the reply code. If this step is - * required, it should immediately follow the AUTHINFO USER command - * (See RFC 2980) - *

- * @param password a valid password. - * @return The reply code received from the server. The server should - * return a 281 or 502 for this command. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int authinfoPass(String password) throws IOException { - String passParameter = "PASS " + password; - return sendCommand(NNTPCommand.AUTHINFO, passParameter); - } - - /*** - * A convenience method to send the NNTP XOVER command to the server, - * receive the reply, and return the reply code. - *

- * @param selectedArticles a String representation of the range of - * article headers required. This may be an article number, or a - * range of article numbers in the form "XXXX-YYYY", where XXXX - * and YYYY are valid article numbers in the current group. It - * also may be of the form "XXX-", meaning "return XXX and all - * following articles" In this revision, the last format is not - * possible (yet). - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int xover(String selectedArticles) throws IOException { - return sendCommand(NNTPCommand.XOVER, selectedArticles); - } - - /*** - * A convenience method to send the NNTP XHDR command to the server, - * receive the reply, and return the reply code. - *

- * @param header a String naming a header line (e.g., "subject"). See - * RFC-1036 for a list of valid header lines. - * @param selectedArticles a String representation of the range of - * article headers required. This may be an article number, or a - * range of article numbers in the form "XXXX-YYYY", where XXXX - * and YYYY are valid article numbers in the current group. It - * also may be of the form "XXX-", meaning "return XXX and all - * following articles" In this revision, the last format is not - * possible (yet). - * @return The reply code received from the server. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int xhdr(String header, String selectedArticles) throws IOException { - StringBuffer command = new StringBuffer(header); - command.append(" "); - command.append(selectedArticles); - return sendCommand(NNTPCommand.XHDR, command.toString()); - } - - /** - * A convenience wrapper for the extended LIST command that takes - * an argument, allowing us to selectively list multiple groups. - *

- * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for - * details. - * @return the reply code received from the server. - * @throws IOException - */ - public int listActive(String wildmat) throws IOException { - StringBuffer command = new StringBuffer("ACTIVE "); - command.append(wildmat); - return sendCommand(NNTPCommand.LIST, command.toString()); - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/nntp/NNTPClient.java b/org/apache/commons/net/nntp/NNTPClient.java deleted file mode 100644 index e10ce90..0000000 --- a/org/apache/commons/net/nntp/NNTPClient.java +++ /dev/null @@ -1,1285 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.StringTokenizer; -import java.util.Vector; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.io.DotTerminatedMessageReader; -import org.apache.commons.net.io.DotTerminatedMessageWriter; -import org.apache.commons.net.io.Util; - -/*** - * NNTPClient encapsulates all the functionality necessary to post and - * retrieve articles from an NNTP server. As with all classes derived - * from {@link org.apache.commons.net.SocketClient}, - * you must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before doing anything, and finally - * {@link org.apache.commons.net.nntp.NNTP#disconnect disconnect() } - * after you're completely finished interacting with the server. - * Remember that the - * {@link org.apache.commons.net.nntp.NNTP#isAllowedToPost isAllowedToPost()} - * method is defined in - * {@link org.apache.commons.net.nntp.NNTP}. - *

- * You should keep in mind that the NNTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period or if the server is being shutdown by the operator or - * some other reason. The NNTP class will detect a - * premature NNTP server connection closing when it receives a - * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } - * response to a command. - * When that occurs, the NNTP class method encountering that reply will throw - * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} - * . - * NNTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException} - * , you must disconnect the connection with - * {@link org.apache.commons.net.nntp.NNTP#disconnect disconnect() } - * to properly clean up the - * system resources used by NNTP. Before disconnecting, you may check the - * last reply code and text with - * {@link org.apache.commons.net.nntp.NNTP#getReplyCode getReplyCode } and - * {@link org.apache.commons.net.nntp.NNTP#getReplyString getReplyString }. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @author Rory Winston - * @author Ted Wise - * @see NNTP - * @see NNTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - ***/ - -public class NNTPClient extends NNTP -{ - - private void __parseArticlePointer(String reply, ArticlePointer pointer) - throws MalformedServerReplyException - { - StringTokenizer tokenizer; - - // Do loop is a kluge to simulate goto - do - { - tokenizer = new StringTokenizer(reply); - - if (tokenizer.countTokens() < 3) - break; - - // Skip numeric response value - tokenizer.nextToken(); - // Get article number - try - { - pointer.articleNumber = Integer.parseInt(tokenizer.nextToken()); - } - catch (NumberFormatException e) - { - break; - } - - // Get article id - pointer.articleId = tokenizer.nextToken(); - return ; - } - while (false); - - throw new MalformedServerReplyException( - "Could not parse article pointer.\nServer reply: " + reply); - } - - - private void __parseGroupReply(String reply, NewsgroupInfo info) - throws MalformedServerReplyException - { - String count, first, last; - StringTokenizer tokenizer; - - // Do loop is a kluge to simulate goto - do - { - tokenizer = new StringTokenizer(reply); - - if (tokenizer.countTokens() < 5) - break; - - // Skip numeric response value - tokenizer.nextToken(); - // Get estimated article count - count = tokenizer.nextToken(); - // Get first article number - first = tokenizer.nextToken(); - // Get last article number - last = tokenizer.nextToken(); - // Get newsgroup name - info._setNewsgroup(tokenizer.nextToken()); - - try - { - info._setArticleCount(Integer.parseInt(count)); - info._setFirstArticle(Integer.parseInt(first)); - info._setLastArticle(Integer.parseInt(last)); - } - catch (NumberFormatException e) - { - break; - } - - info._setPostingPermission(NewsgroupInfo.UNKNOWN_POSTING_PERMISSION); - return ; - } - while (false); - - throw new MalformedServerReplyException( - "Could not parse newsgroup info.\nServer reply: " + reply); - } - - - private NewsgroupInfo __parseNewsgroupListEntry(String entry) - { - NewsgroupInfo result; - StringTokenizer tokenizer; - int lastNum, firstNum; - String last, first, permission; - - result = new NewsgroupInfo(); - tokenizer = new StringTokenizer(entry); - - if (tokenizer.countTokens() < 4) - return null; - - result._setNewsgroup(tokenizer.nextToken()); - last = tokenizer.nextToken(); - first = tokenizer.nextToken(); - permission = tokenizer.nextToken(); - - try - { - lastNum = Integer.parseInt(last); - firstNum = Integer.parseInt(first); - result._setFirstArticle(firstNum); - result._setLastArticle(lastNum); - - if((firstNum == 0) && (lastNum == 0)) - result._setArticleCount(0); - else - result._setArticleCount(lastNum - firstNum + 1); - } - catch (NumberFormatException e) - { - return null; - } - - switch (permission.charAt(0)) - { - case 'y': - case 'Y': - result._setPostingPermission( - NewsgroupInfo.PERMITTED_POSTING_PERMISSION); - break; - case 'n': - case 'N': - result._setPostingPermission( - NewsgroupInfo.PROHIBITED_POSTING_PERMISSION); - break; - case 'm': - case 'M': - result._setPostingPermission( - NewsgroupInfo.MODERATED_POSTING_PERMISSION); - break; - default: - result._setPostingPermission( - NewsgroupInfo.UNKNOWN_POSTING_PERMISSION); - break; - } - - return result; - } - - private NewsgroupInfo[] __readNewsgroupListing() throws IOException - { - int size; - String line; - Vector list; - BufferedReader reader; - NewsgroupInfo tmp, info[]; - - reader = new BufferedReader(new DotTerminatedMessageReader(_reader_)); - // Start of with a big vector because we may be reading a very large - // amount of groups. - list = new Vector(2048); - - while ((line = reader.readLine()) != null) - { - tmp = __parseNewsgroupListEntry(line); - if (tmp != null) - list.addElement(tmp); - else - throw new MalformedServerReplyException(line); - } - - if ((size = list.size()) < 1) - return new NewsgroupInfo[0]; - - info = new NewsgroupInfo[size]; - list.copyInto(info); - - return info; - } - - - private Reader __retrieve(int command, - String articleId, ArticlePointer pointer) - throws IOException - { - Reader reader; - - if (articleId != null) - { - if (!NNTPReply.isPositiveCompletion(sendCommand(command, articleId))) - return null; - } - else - { - if (!NNTPReply.isPositiveCompletion(sendCommand(command))) - return null; - } - - - if (pointer != null) - __parseArticlePointer(getReplyString(), pointer); - - reader = new DotTerminatedMessageReader(_reader_); - return reader; - } - - - private Reader __retrieve(int command, - int articleNumber, ArticlePointer pointer) - throws IOException - { - Reader reader; - - if (!NNTPReply.isPositiveCompletion(sendCommand(command, - Integer.toString(articleNumber)))) - return null; - - if (pointer != null) - __parseArticlePointer(getReplyString(), pointer); - - reader = new DotTerminatedMessageReader(_reader_); - return reader; - } - - - - /*** - * Retrieves an article from the NNTP server. The article is referenced - * by its unique article identifier (including the enclosing < and >). - * The article number and identifier contained in the server reply - * are returned through an ArticlePointer. The articleId - * field of the ArticlePointer cannot always be trusted because some - * NNTP servers do not correctly follow the RFC 977 reply format. - *

- * A DotTerminatedMessageReader is returned from which the article can - * be read. If the article does not exist, null is returned. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The NNTP protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the NNTP connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param articleId The unique article identifier of the article to - * retrieve. If this parameter is null, the currently selected - * article is retrieved. - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return A DotTerminatedMessageReader instance from which the article - * be read. null if the article does not exist. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Reader retrieveArticle(String articleId, ArticlePointer pointer) - throws IOException - { - return __retrieve(NNTPCommand.ARTICLE, articleId, pointer); - - } - - /*** Same as retrieveArticle(articleId, null) ***/ - public Reader retrieveArticle(String articleId) throws IOException - { - return retrieveArticle(articleId, null); - } - - /*** Same as retrieveArticle(null) ***/ - public Reader retrieveArticle() throws IOException - { - return retrieveArticle(null); - } - - - /*** - * Retrieves an article from the currently selected newsgroup. The - * article is referenced by its article number. - * The article number and identifier contained in the server reply - * are returned through an ArticlePointer. The articleId - * field of the ArticlePointer cannot always be trusted because some - * NNTP servers do not correctly follow the RFC 977 reply format. - *

- * A DotTerminatedMessageReader is returned from which the article can - * be read. If the article does not exist, null is returned. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The NNTP protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the NNTP connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param articleNumber The number of the the article to - * retrieve. - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return A DotTerminatedMessageReader instance from which the article - * be read. null if the article does not exist. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Reader retrieveArticle(int articleNumber, ArticlePointer pointer) - throws IOException - { - return __retrieve(NNTPCommand.ARTICLE, articleNumber, pointer); - } - - /*** Same as retrieveArticle(articleNumber, null) ***/ - public Reader retrieveArticle(int articleNumber) throws IOException - { - return retrieveArticle(articleNumber, null); - } - - - - /*** - * Retrieves an article header from the NNTP server. The article is - * referenced - * by its unique article identifier (including the enclosing < and >). - * The article number and identifier contained in the server reply - * are returned through an ArticlePointer. The articleId - * field of the ArticlePointer cannot always be trusted because some - * NNTP servers do not correctly follow the RFC 977 reply format. - *

- * A DotTerminatedMessageReader is returned from which the article can - * be read. If the article does not exist, null is returned. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The NNTP protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the NNTP connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param articleId The unique article identifier of the article whose - * header is being retrieved. If this parameter is null, the - * header of the currently selected article is retrieved. - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return A DotTerminatedMessageReader instance from which the article - * header can be read. null if the article does not exist. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Reader retrieveArticleHeader(String articleId, ArticlePointer pointer) - throws IOException - { - return __retrieve(NNTPCommand.HEAD, articleId, pointer); - - } - - /*** Same as retrieveArticleHeader(articleId, null) ***/ - public Reader retrieveArticleHeader(String articleId) throws IOException - { - return retrieveArticleHeader(articleId, null); - } - - /*** Same as retrieveArticleHeader(null) ***/ - public Reader retrieveArticleHeader() throws IOException - { - return retrieveArticleHeader(null); - } - - - /*** - * Retrieves an article header from the currently selected newsgroup. The - * article is referenced by its article number. - * The article number and identifier contained in the server reply - * are returned through an ArticlePointer. The articleId - * field of the ArticlePointer cannot always be trusted because some - * NNTP servers do not correctly follow the RFC 977 reply format. - *

- * A DotTerminatedMessageReader is returned from which the article can - * be read. If the article does not exist, null is returned. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The NNTP protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the NNTP connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param articleNumber The number of the the article whose header is - * being retrieved. - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return A DotTerminatedMessageReader instance from which the article - * header can be read. null if the article does not exist. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Reader retrieveArticleHeader(int articleNumber, - ArticlePointer pointer) - throws IOException - { - return __retrieve(NNTPCommand.HEAD, articleNumber, pointer); - } - - - /*** Same as retrieveArticleHeader(articleNumber, null) ***/ - public Reader retrieveArticleHeader(int articleNumber) throws IOException - { - return retrieveArticleHeader(articleNumber, null); - } - - - - /*** - * Retrieves an article body from the NNTP server. The article is - * referenced - * by its unique article identifier (including the enclosing < and >). - * The article number and identifier contained in the server reply - * are returned through an ArticlePointer. The articleId - * field of the ArticlePointer cannot always be trusted because some - * NNTP servers do not correctly follow the RFC 977 reply format. - *

- * A DotTerminatedMessageReader is returned from which the article can - * be read. If the article does not exist, null is returned. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The NNTP protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the NNTP connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param articleId The unique article identifier of the article whose - * body is being retrieved. If this parameter is null, the - * body of the currently selected article is retrieved. - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return A DotTerminatedMessageReader instance from which the article - * body can be read. null if the article does not exist. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Reader retrieveArticleBody(String articleId, ArticlePointer pointer) - throws IOException - { - return __retrieve(NNTPCommand.BODY, articleId, pointer); - - } - - /*** Same as retrieveArticleBody(articleId, null) ***/ - public Reader retrieveArticleBody(String articleId) throws IOException - { - return retrieveArticleBody(articleId, null); - } - - /*** Same as retrieveArticleBody(null) ***/ - public Reader retrieveArticleBody() throws IOException - { - return retrieveArticleBody(null); - } - - - /*** - * Retrieves an article body from the currently selected newsgroup. The - * article is referenced by its article number. - * The article number and identifier contained in the server reply - * are returned through an ArticlePointer. The articleId - * field of the ArticlePointer cannot always be trusted because some - * NNTP servers do not correctly follow the RFC 977 reply format. - *

- * A DotTerminatedMessageReader is returned from which the article can - * be read. If the article does not exist, null is returned. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The NNTP protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the NNTP connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param articleNumber The number of the the article whose body is - * being retrieved. - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return A DotTerminatedMessageReader instance from which the article - * body can be read. null if the article does not exist. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Reader retrieveArticleBody(int articleNumber, - ArticlePointer pointer) - throws IOException - { - return __retrieve(NNTPCommand.BODY, articleNumber, pointer); - } - - - /*** Same as retrieveArticleBody(articleNumber, null) ***/ - public Reader retrieveArticleBody(int articleNumber) throws IOException - { - return retrieveArticleBody(articleNumber, null); - } - - - /*** - * Select the specified newsgroup to be the target of for future article - * retrieval and posting operations. Also return the newsgroup - * information contained in the server reply through the info parameter. - *

- * @param newsgroup The newsgroup to select. - * @param info A parameter through which the newsgroup information of - * the selected newsgroup contained in the server reply is returned. - * Set this to null if you do not desire this information. - * @return True if the newsgroup exists and was selected, false otherwise. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean selectNewsgroup(String newsgroup, NewsgroupInfo info) - throws IOException - { - if (!NNTPReply.isPositiveCompletion(group(newsgroup))) - return false; - - if (info != null) - __parseGroupReply(getReplyString(), info); - - return true; - } - - /*** Same as selectNewsgroup(newsgroup, null) ***/ - public boolean selectNewsgroup(String newsgroup) throws IOException - { - return selectNewsgroup(newsgroup, null); - } - - /*** - * List the command help from the server. - *

- * @return The sever help information. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String listHelp() throws IOException - { - StringWriter help; - Reader reader; - - if (!NNTPReply.isInformational(help())) - return null; - - help = new StringWriter(); - reader = new DotTerminatedMessageReader(_reader_); - Util.copyReader(reader, help); - reader.close(); - help.close(); - return help.toString(); - } - - - /*** - * Select an article by its unique identifier (including enclosing - * < and >) and return its article number and id through the - * pointer parameter. This is achieved through the STAT command. - * According to RFC 977, this will NOT set the current article pointer - * on the server. To do that, you must reference the article by its - * number. - *

- * @param articleId The unique article identifier of the article that - * is being selectedd. If this parameter is null, the - * body of the current article is selected - * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return True if successful, false if not. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean selectArticle(String articleId, ArticlePointer pointer) - throws IOException - { - if (articleId != null) - { - if (!NNTPReply.isPositiveCompletion(stat(articleId))) - return false; - } - else - { - if (!NNTPReply.isPositiveCompletion(stat())) - return false; - } - - if (pointer != null) - __parseArticlePointer(getReplyString(), pointer); - - return true; - } - - /**** Same as selectArticle(articleId, null) ***/ - public boolean selectArticle(String articleId) throws IOException - { - return selectArticle(articleId, null); - } - - /**** - * Same as selectArticle(null, articleId) . Useful - * for retrieving the current article number. - ***/ - public boolean selectArticle(ArticlePointer pointer) throws IOException - { - return selectArticle(null, pointer); - } - - - /*** - * Select an article in the currently selected newsgroup by its number. - * and return its article number and id through the - * pointer parameter. This is achieved through the STAT command. - * According to RFC 977, this WILL set the current article pointer - * on the server. Use this command to select an article before retrieving - * it, or to obtain an article's unique identifier given its number. - *

- * @param articleNumber The number of the article to select from the - * currently selected newsgroup. - * @param pointer A parameter through which to return the article's - * number and unique id. Although the articleId field cannot always - * be trusted because of server deviations from RFC 977 reply formats, - * we haven't found a server that misformats this information in response - * to this particular command. You may set this parameter to null if - * you do not desire to retrieve the returned article information. - * @return True if successful, false if not. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean selectArticle(int articleNumber, ArticlePointer pointer) - throws IOException - { - if (!NNTPReply.isPositiveCompletion(stat(articleNumber))) - return false; - - if (pointer != null) - __parseArticlePointer(getReplyString(), pointer); - - return true; - } - - - /*** Same as selectArticle(articleNumber, null) ***/ - public boolean selectArticle(int articleNumber) throws IOException - { - return selectArticle(articleNumber, null); - } - - - /*** - * Select the article preceeding the currently selected article in the - * currently selected newsgroup and return its number and unique id - * through the pointer parameter. Because of deviating server - * implementations, the articleId information cannot be trusted. To - * obtain the article identifier, issue a - * selectArticle(pointer.articleNumber, pointer) immediately - * afterward. - *

- * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return True if successful, false if not (e.g., there is no previous - * article). - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean selectPreviousArticle(ArticlePointer pointer) - throws IOException - { - if (!NNTPReply.isPositiveCompletion(last())) - return false; - - if (pointer != null) - __parseArticlePointer(getReplyString(), pointer); - - return true; - } - - /*** Same as selectPreviousArticle(null) ***/ - public boolean selectPreviousArticle() throws IOException - { - return selectPreviousArticle(null); - } - - - /*** - * Select the article following the currently selected article in the - * currently selected newsgroup and return its number and unique id - * through the pointer parameter. Because of deviating server - * implementations, the articleId information cannot be trusted. To - * obtain the article identifier, issue a - * selectArticle(pointer.articleNumber, pointer) immediately - * afterward. - *

- * @param pointer A parameter through which to return the article's - * number and unique id. The articleId field cannot always be trusted - * because of server deviations from RFC 977 reply formats. You may - * set this parameter to null if you do not desire to retrieve the - * returned article information. - * @return True if successful, false if not (e.g., there is no following - * article). - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean selectNextArticle(ArticlePointer pointer) throws IOException - { - if (!NNTPReply.isPositiveCompletion(next())) - return false; - - if (pointer != null) - __parseArticlePointer(getReplyString(), pointer); - - return true; - } - - - /*** Same as selectNextArticle(null) ***/ - public boolean selectNextArticle() throws IOException - { - return selectNextArticle(null); - } - - - /*** - * List all newsgroups served by the NNTP server. If no newsgroups - * are served, a zero length array will be returned. If the command - * fails, null will be returned. - *

- * @return An array of NewsgroupInfo instances containing the information - * for each newsgroup served by the NNTP server. If no newsgroups - * are served, a zero length array will be returned. If the command - * fails, null will be returned. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public NewsgroupInfo[] listNewsgroups() throws IOException - { - if (!NNTPReply.isPositiveCompletion(list())) - return null; - - return __readNewsgroupListing(); - } - - /** - * An overloaded listNewsgroups() command that allows us to - * specify with a pattern what groups we want to list. Wraps the - * LIST ACTIVE command. - *

- * @param wildmat a pseudo-regex pattern (cf. RFC 2980) - * @return An array of NewsgroupInfo instances containing the information - * for each newsgroup served by the NNTP server corresponding to the - * supplied pattern. If no such newsgroups are served, a zero length - * array will be returned. If the command fails, null will be returned. - * @throws IOException - */ - public NewsgroupInfo[] listNewsgroups(String wildmat) throws IOException - { - if(!NNTPReply.isPositiveCompletion(listActive(wildmat))) - return null; - return __readNewsgroupListing(); - } - - - /*** - * List all new newsgroups added to the NNTP server since a particular - * date subject to the conditions of the specified query. If no new - * newsgroups were added, a zero length array will be returned. If the - * command fails, null will be returned. - *

- * @param query The query restricting how to search for new newsgroups. - * @return An array of NewsgroupInfo instances containing the information - * for each new newsgroup added to the NNTP server. If no newsgroups - * were added, a zero length array will be returned. If the command - * fails, null will be returned. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public NewsgroupInfo[] listNewNewsgroups(NewGroupsOrNewsQuery query) - throws IOException - { - if (!NNTPReply.isPositiveCompletion(newgroups( - query.getDate(), query.getTime(), - query.isGMT(), query.getDistributions()))) - return null; - - return __readNewsgroupListing(); - } - - - /*** - * List all new articles added to the NNTP server since a particular - * date subject to the conditions of the specified query. If no new - * new news is found, a zero length array will be returned. If the - * command fails, null will be returned. You must add at least one - * newsgroup to the query, else the command will fail. Each String - * in the returned array is a unique message identifier including the - * enclosing < and >. - *

- * @param query The query restricting how to search for new news. You - * must add at least one newsgroup to the query. - * @return An array of String instances containing the unique message - * identifiers for each new article added to the NNTP server. If no - * new news is found, a zero length array will be returned. If the - * command fails, null will be returned. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String[] listNewNews(NewGroupsOrNewsQuery query) - throws IOException - { - int size; - String line; - Vector list; - String[] result; - BufferedReader reader; - - if (!NNTPReply.isPositiveCompletion(newnews( - query.getNewsgroups(), query.getDate(), query.getTime(), - query.isGMT(), query.getDistributions()))) - return null; - - list = new Vector(); - reader = new BufferedReader(new DotTerminatedMessageReader(_reader_)); - - while ((line = reader.readLine()) != null) - list.addElement(line); - - size = list.size(); - - if (size < 1) - return new String[0]; - - result = new String[size]; - list.copyInto(result); - - return result; - } - - /*** - * There are a few NNTPClient methods that do not complete the - * entire sequence of NNTP commands to complete a transaction. These - * commands require some action by the programmer after the reception - * of a positive preliminary command. After the programmer's code - * completes its actions, it must call this method to receive - * the completion reply from the server and verify the success of the - * entire transaction. - *

- * For example - *

-     * writer = client.postArticle();
-     * if(writer == null) // failure
-     *   return false;
-     * header = new SimpleNNTPHeader("foobar@foo.com", "Just testing");
-     * header.addNewsgroup("alt.test");
-     * writer.write(header.toString());
-     * writer.write("This is just a test");
-     * writer.close();
-     * if(!client.completePendingCommand()) // failure
-     *   return false;
-     * 
- *

- * @return True if successfully completed, false if not. - * @exception NNTPConnectionClosedException - * If the NNTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send NNTP reply code 400. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean completePendingCommand() throws IOException - { - return NNTPReply.isPositiveCompletion(getReply()); - } - - /*** - * Post an article to the NNTP server. This method returns a - * DotTerminatedMessageWriter instance to which the article can be - * written. Null is returned if the posting attempt fails. You - * should check {@link NNTP#isAllowedToPost isAllowedToPost() } - * before trying to post. However, a posting - * attempt can fail due to malformed headers. - *

- * You must not issue any commands to the NNTP server (i.e., call any - * (other methods) until you finish writing to the returned Writer - * instance and close it. The NNTP protocol uses the same stream for - * issuing commands as it does for returning results. Therefore the - * returned Writer actually writes directly to the NNTP connection. - * After you close the writer, you can execute new commands. If you - * do not follow these requirements your program will not work properly. - *

- * Different NNTP servers will require different header formats, but - * you can use the provided - * {@link org.apache.commons.net.nntp.SimpleNNTPHeader} - * class to construct the bare minimum acceptable header for most - * news readers. To construct more complicated headers you should - * refer to RFC 822. When the Java Mail API is finalized, you will be - * able to use it to compose fully compliant Internet text messages. - * The DotTerminatedMessageWriter takes care of doubling line-leading - * dots and ending the message with a single dot upon closing, so all - * you have to worry about is writing the header and the message. - *

- * Upon closing the returned Writer, you need to call - * {@link #completePendingCommand completePendingCommand() } - * to finalize the posting and verify its success or failure from - * the server reply. - *

- * @return A DotTerminatedMessageWriter to which the article (including - * header) can be written. Returns null if the command fails. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - - public Writer postArticle() throws IOException - { - if (!NNTPReply.isPositiveIntermediate(post())) - return null; - - return new DotTerminatedMessageWriter(_writer_); - } - - - public Writer forwardArticle(String articleId) throws IOException - { - if (!NNTPReply.isPositiveIntermediate(ihave(articleId))) - return null; - - return new DotTerminatedMessageWriter(_writer_); - } - - - /*** - * Logs out of the news server gracefully by sending the QUIT command. - * However, you must still disconnect from the server before you can open - * a new connection. - *

- * @return True if successfully completed, false if not. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean logout() throws IOException - { - return NNTPReply.isPositiveCompletion(quit()); - } - - - /** - * Log into a news server by sending the AUTHINFO USER/AUTHINFO - * PASS command sequence. This is usually sent in response to a - * 480 reply code from the NNTP server. - *

- * @param username a valid username - * @param password the corresponding password - * @return True for successful login, false for a failure - * @throws IOException - */ - public boolean authenticate(String username, String password) - throws IOException - { - int replyCode = authinfoUser(username); - - if (replyCode == NNTPReply.MORE_AUTH_INFO_REQUIRED) - { - replyCode = authinfoPass(password); - - if (replyCode == NNTPReply.AUTHENTICATION_ACCEPTED) - { - _isAllowedToPost = true; - return true; - } - } - return false; - } - - /*** - * Private implementation of XOVER functionality. - * - * See {@link NNTP#xover} - * for legal agument formats. Alternatively, read RFC 2980 :-) - *

- * @param articleRange - * @return Returns a DotTerminatedMessageReader if successful, null - * otherwise - * @exception IOException - */ - private Reader __retrieveArticleInfo(String articleRange) - throws IOException - { - if (!NNTPReply.isPositiveCompletion(xover(articleRange))) - return null; - - return new DotTerminatedMessageReader(_reader_); - } - - /** - * Return article headers for a specified post. - *

- * @param articleNumber the article to retrieve headers for - * @return a DotTerminatedReader if successful, null otherwise - * @throws IOException - */ - public Reader retrieveArticleInfo(int articleNumber) throws IOException - { - return __retrieveArticleInfo(Integer.toString(articleNumber)); - } - - /** - * Return article headers for all articles between lowArticleNumber - * and highArticleNumber, inclusively. - *

- * @param lowArticleNumber - * @param highArticleNumber - * @return a DotTerminatedReader if successful, null otherwise - * @throws IOException - */ - public Reader retrieveArticleInfo(int lowArticleNumber, - int highArticleNumber) - throws IOException - { - return - __retrieveArticleInfo(lowArticleNumber + "-" + - highArticleNumber); - } - - /*** - * Private implementation of XHDR functionality. - * - * See {@link NNTP#xhdr} - * for legal agument formats. Alternatively, read RFC 1036. - *

- * @param header - * @param articleRange - * @return Returns a DotTerminatedMessageReader if successful, null - * otherwise - * @exception IOException - */ - private Reader __retrieveHeader(String header, String articleRange) - throws IOException - { - if (!NNTPReply.isPositiveCompletion(xhdr(header, articleRange))) - return null; - - return new DotTerminatedMessageReader(_reader_); - } - - /** - * Return an article header for a specified post. - *

- * @param header the header to retrieve - * @param articleNumber the article to retrieve the header for - * @return a DotTerminatedReader if successful, null otherwise - * @throws IOException - */ - public Reader retrieveHeader(String header, int articleNumber) - throws IOException - { - return __retrieveHeader(header, Integer.toString(articleNumber)); - } - - /** - * Return an article header for all articles between lowArticleNumber - * and highArticleNumber, inclusively. - *

- * @param header - * @param lowArticleNumber - * @param highArticleNumber - * @return a DotTerminatedReader if successful, null otherwise - * @throws IOException - */ - public Reader retrieveHeader(String header, int lowArticleNumber, - int highArticleNumber) - throws IOException - { - return - __retrieveHeader(header,lowArticleNumber + "-" + highArticleNumber); - } -} - - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/nntp/NNTPCommand.java b/org/apache/commons/net/nntp/NNTPCommand.java deleted file mode 100644 index 09f4015..0000000 --- a/org/apache/commons/net/nntp/NNTPCommand.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -/*** - * NNTPCommand stores a set of constants for NNTP command codes. To interpret - * the meaning of the codes, familiarity with RFC 977 is assumed. - *

- * @author Daniel F. Savarese - * @author Rory Winston - * @author Ted Wise - ***/ - -public final class NNTPCommand -{ - - public static final int ARTICLE = 0; - public static final int BODY = 1; - public static final int GROUP = 2; - public static final int HEAD = 3; - public static final int HELP = 4; - public static final int IHAVE = 5; - public static final int LAST = 6; - public static final int LIST = 7; - public static final int NEWGROUPS = 8; - public static final int NEWNEWS = 9; - public static final int NEXT = 10; - public static final int POST = 11; - public static final int QUIT = 12; - public static final int SLAVE = 13; - public static final int STAT = 14; - public static final int AUTHINFO = 15; - public static final int XOVER = 16; - public static final int XHDR = 17; - - // Cannot be instantiated - private NNTPCommand() - {} - - static final String[] _commands = { - "ARTICLE", "BODY", "GROUP", "HEAD", "HELP", "IHAVE", "LAST", "LIST", - "NEWGROUPS", "NEWNEWS", "NEXT", "POST", "QUIT", "SLAVE", "STAT", - "AUTHINFO", "XOVER", "XHDR" - }; - - - /*** - * Retrieve the NNTP protocol command string corresponding to a specified - * command code. - *

- * @param command The command code. - * @return The NNTP protcol command string corresponding to a specified - * command code. - ***/ - public static final String getCommand(int command) - { - return _commands[command]; - } - -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/nntp/NNTPConnectionClosedException.java b/org/apache/commons/net/nntp/NNTPConnectionClosedException.java deleted file mode 100644 index 948ed12..0000000 --- a/org/apache/commons/net/nntp/NNTPConnectionClosedException.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -import java.io.IOException; - -/*** - * NNTPConnectionClosedException is used to indicate the premature or - * unexpected closing of an NNTP connection resulting from a - * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED } - * response (NNTP reply code 400) to a - * failed NNTP command. This exception is derived from IOException and - * therefore may be caught either as an IOException or specifically as an - * NNTPConnectionClosedException. - *

- *

- * @author Daniel F. Savarese - * @see NNTP - * @see NNTPClient - ***/ - -public final class NNTPConnectionClosedException extends IOException -{ - - /*** Constructs a NNTPConnectionClosedException with no message ***/ - public NNTPConnectionClosedException() - { - super(); - } - - /*** - * Constructs a NNTPConnectionClosedException with a specified message. - *

- * @param message The message explaining the reason for the exception. - ***/ - public NNTPConnectionClosedException(String message) - { - super(message); - } - -} diff --git a/org/apache/commons/net/nntp/NNTPReply.java b/org/apache/commons/net/nntp/NNTPReply.java deleted file mode 100644 index f7d0fbd..0000000 --- a/org/apache/commons/net/nntp/NNTPReply.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -/*** - * NNTPReply stores a set of constants for NNTP reply codes. To interpret - * the meaning of the codes, familiarity with RFC 977 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 977. For those who think in terms of the actual reply code values, - * a set of CODE_NUM constants are provided where NUM is the numerical value - * of the code. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class NNTPReply -{ - - public static final int CODE_100 = 100; - public static final int CODE_199 = 199; - public static final int CODE_200 = 200; - public static final int CODE_201 = 201; - public static final int CODE_202 = 202; - public static final int CODE_205 = 205; - public static final int CODE_211 = 211; - public static final int CODE_215 = 215; - public static final int CODE_220 = 220; - public static final int CODE_221 = 221; - public static final int CODE_222 = 222; - public static final int CODE_223 = 223; - public static final int CODE_230 = 230; - public static final int CODE_231 = 231; - public static final int CODE_235 = 235; - public static final int CODE_240 = 240; - public static final int CODE_281 = 281; - public static final int CODE_335 = 335; - public static final int CODE_340 = 340; - public static final int CODE_381 = 381; - public static final int CODE_400 = 400; - public static final int CODE_408 = 408; - public static final int CODE_411 = 411; - public static final int CODE_412 = 412; - public static final int CODE_420 = 420; - public static final int CODE_421 = 421; - public static final int CODE_422 = 422; - public static final int CODE_423 = 423; - public static final int CODE_430 = 430; - public static final int CODE_435 = 435; - public static final int CODE_436 = 436; - public static final int CODE_437 = 437; - public static final int CODE_440 = 440; - public static final int CODE_441 = 441; - public static final int CODE_482 = 482; - public static final int CODE_500 = 500; - public static final int CODE_501 = 501; - public static final int CODE_502 = 502; - public static final int CODE_503 = 503; - - public static final int HELP_TEXT_FOLLOWS = CODE_100; - public static final int DEBUG_OUTPUT = CODE_199; - public static final int SERVER_READY_POSTING_ALLOWED = CODE_200; - public static final int SERVER_READY_POSTING_NOT_ALLOWED = CODE_201; - public static final int SLAVE_STATUS_NOTED = CODE_202; - public static final int CLOSING_CONNECTION = CODE_205; - public static final int GROUP_SELECTED = CODE_211; - public static final int ARTICLE_RETRIEVED_HEAD_AND_BODY_FOLLOW = CODE_220; - public static final int ARTICLE_RETRIEVED_HEAD_FOLLOWS = CODE_221; - public static final int ARTICLE_RETRIEVED_BODY_FOLLOWS = CODE_222; - public static final int - ARTICLE_RETRIEVED_REQUEST_TEXT_SEPARATELY = CODE_223; - public static final int ARTICLE_LIST_BY_MESSAGE_ID_FOLLOWS = CODE_230; - public static final int NEW_NEWSGROUP_LIST_FOLLOWS = CODE_231; - public static final int ARTICLE_TRANSFERRED_OK = CODE_235; - public static final int ARTICLE_POSTED_OK = CODE_240; - public static final int AUTHENTICATION_ACCEPTED = CODE_281; - public static final int SEND_ARTICLE_TO_TRANSFER = CODE_335; - public static final int SEND_ARTICLE_TO_POST = CODE_340; - public static final int MORE_AUTH_INFO_REQUIRED = CODE_381; - public static final int SERVICE_DISCONTINUED = CODE_400; - public static final int NO_SUCH_NEWSGROUP = CODE_411; - public static final int AUTHENTICATION_REQUIRED = CODE_408; - public static final int NO_NEWSGROUP_SELECTED = CODE_412; - public static final int NO_CURRENT_ARTICLE_SELECTED = CODE_420; - public static final int NO_NEXT_ARTICLE = CODE_421; - public static final int NO_PREVIOUS_ARTICLE = CODE_422; - public static final int NO_SUCH_ARTICLE_NUMBER = CODE_423; - public static final int NO_SUCH_ARTICLE_FOUND = CODE_430; - public static final int ARTICLE_NOT_WANTED = CODE_435; - public static final int TRANSFER_FAILED = CODE_436; - public static final int ARTICLE_REJECTED = CODE_437; - public static final int POSTING_NOT_ALLOWED = CODE_440; - public static final int POSTING_FAILED = CODE_441; - public static final int AUTHENTICATION_REJECTED = CODE_482; - public static final int COMMAND_NOT_RECOGNIZED = CODE_500; - public static final int COMMAND_SYNTAX_ERROR = CODE_501; - public static final int PERMISSION_DENIED = CODE_502; - public static final int PROGRAM_FAULT = CODE_503; - - // Cannot be instantiated - - private NNTPReply() - {} - - /*** - * Determine if a reply code is an informational response. All - * codes beginning with a 1 are positive informational responses. - * Informational responses are used to provide human readable - * information such as help text. - *

- * @param reply The reply code to test. - * @return True if a reply code is an informational response, false - * if not. - ***/ - public static boolean isInformational(int reply) - { - return (reply >= 100 && reply < 200); - } - - /*** - * Determine if a reply code is a positive completion response. All - * codes beginning with a 2 are positive completion responses. - * The NNTP server will send a positive completion response on the final - * successful completion of a command. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive completion response, false - * if not. - ***/ - public static boolean isPositiveCompletion(int reply) - { - return (reply >= 200 && reply < 300); - } - - /*** - * Determine if a reply code is a positive intermediate response. All - * codes beginning with a 3 are positive intermediate responses. - * The NNTP server will send a positive intermediate response on the - * successful completion of one part of a multi-part command or - * sequence of commands. For example, after a successful POST command, - * a positive intermediate response will be sent to indicate that the - * server is ready to receive the article to be posted. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive intermediate response, false - * if not. - ***/ - public static boolean isPositiveIntermediate(int reply) - { - return (reply >= 300 && reply < 400); - } - - /*** - * Determine if a reply code is a negative transient response. All - * codes beginning with a 4 are negative transient responses. - * The NNTP server will send a negative transient response on the - * failure of a correctly formatted command that could not be performed - * for some reason. For example, retrieving an article that does not - * exist will result in a negative transient response. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative transient response, false - * if not. - ***/ - public static boolean isNegativeTransient(int reply) - { - return (reply >= 400 && reply < 500); - } - - /*** - * Determine if a reply code is a negative permanent response. All - * codes beginning with a 5 are negative permanent responses. - * The NNTP server will send a negative permanent response when - * it does not implement a command, a command is incorrectly formatted, - * or a serious program error occurs. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative permanent response, false - * if not. - ***/ - public static boolean isNegativePermanent(int reply) - { - return (reply >= 500 && reply < 600); - } - -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java b/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java deleted file mode 100644 index a0d9aeb..0000000 --- a/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -import java.util.Calendar; - -/*** - * The NewGroupsOrNewsQuery class. This is used to issue NNTP NEWGROUPS and - * NEWNEWS queries, implemented by - * {@link org.apache.commons.net.nntp.NNTPClient#listNewNewsgroups listNewNewsGroups } - * and - * {@link org.apache.commons.net.nntp.NNTPClient#listNewNews listNewNews } - * respectively. It prevents you from having to format - * date, time, distribution, and newgroup arguments. - *

- * You might use the class as follows: - *

- * query = new NewsGroupsOrNewsQuery(new GregorianCalendar(97, 11, 15), false);
- * query.addDistribution("comp");
- * NewsgroupInfo[] newsgroups = client.listNewgroups(query);
- * 
- * This will retrieve the list of newsgroups starting with the comp. - * distribution prefix created since midnight 11/15/97. - *

- *

- * @author Daniel F. Savarese - * @see NNTPClient - ***/ - -public final class NewGroupsOrNewsQuery -{ - private String __date, __time; - private StringBuffer __distributions; - private StringBuffer __newsgroups; - private boolean __isGMT; - - - /*** - * Creates a new query using the given time as a reference point. - *

- * @param date The date since which new groups or news have arrived. - * @param gmt True if the date should be considered as GMT, false if not. - ***/ - public NewGroupsOrNewsQuery(Calendar date, boolean gmt) - { - int num; - String str; - StringBuffer buffer; - - __distributions = null; - __newsgroups = null; - __isGMT = gmt; - - buffer = new StringBuffer(); - - // Get year - num = date.get(Calendar.YEAR); - str = Integer.toString(num); - num = str.length(); - - if (num >= 2) - buffer.append(str.substring(num - 2)); - else - buffer.append("00"); - - // Get month - num = date.get(Calendar.MONTH) + 1; - str = Integer.toString(num); - num = str.length(); - - if (num == 1) - { - buffer.append('0'); - buffer.append(str); - } - else if (num == 2) - buffer.append(str); - else - buffer.append("01"); - - // Get day - num = date.get(Calendar.DAY_OF_MONTH); - str = Integer.toString(num); - num = str.length(); - - if (num == 1) - { - buffer.append('0'); - buffer.append(str); - } - else if (num == 2) - buffer.append(str); - else - buffer.append("01"); - - __date = buffer.toString(); - - buffer.setLength(0); - - // Get hour - num = date.get(Calendar.HOUR_OF_DAY); - str = Integer.toString(num); - num = str.length(); - - if (num == 1) - { - buffer.append('0'); - buffer.append(str); - } - else if (num == 2) - buffer.append(str); - else - buffer.append("00"); - - // Get minutes - num = date.get(Calendar.MINUTE); - str = Integer.toString(num); - num = str.length(); - - if (num == 1) - { - buffer.append('0'); - buffer.append(str); - } - else if (num == 2) - buffer.append(str); - else - buffer.append("00"); - - - // Get seconds - num = date.get(Calendar.SECOND); - str = Integer.toString(num); - num = str.length(); - - if (num == 1) - { - buffer.append('0'); - buffer.append(str); - } - else if (num == 2) - buffer.append(str); - else - buffer.append("00"); - - __time = buffer.toString(); - } - - - /*** - * Add a newsgroup to the list of newsgroups being queried. Newsgroups - * added this way are only meaningful to the NEWNEWS command. Newsgroup - * names may include the * wildcard, as in - * comp.lang.* or comp.lang.java.* . Adding - * at least one newsgroup is mandatory for the NEWNEWS command. - *

- * @param newsgroup The newsgroup to add to the list of groups to be - * checked for new news. - ***/ - public void addNewsgroup(String newsgroup) - { - if (__newsgroups != null) - __newsgroups.append(','); - else - __newsgroups = new StringBuffer(); - __newsgroups.append(newsgroup); - } - - - /*** - * Add a newsgroup to the list of newsgroups being queried, but indicate - * that group should not be checked for new news. Newsgroups - * added this way are only meaningful to the NEWNEWS command. - * Newsgroup names may include the * wildcard, as in - * comp.lang.* or comp.lang.java.* . - *

- * The following would create a query that searched for new news in - * all comp.lang.java newsgroups except for comp.lang.java.advocacy. - *

-     * query.addNewsgroup("comp.lang.java.*");
-     * query.omitNewsgroup("comp.lang.java.advocacy");
-     * 
- *

- * @param newsgroup The newsgroup to add to the list of groups to be - * checked for new news, but which should be omitted from - * the search for new news.. - ***/ - public void omitNewsgroup(String newsgroup) - { - addNewsgroup("!" + newsgroup); - } - - - /*** - * Add a distribution group to the query. The distribution part of a - * newsgroup is the segment of the name preceding the first dot (e.g., - * comp, alt, rec). Only those newsgroups matching one of the - * distributions or, in the case of NEWNEWS, an article in a newsgroup - * matching one of the distributions, will be reported as a query result. - * Adding distributions is purely optional. - *

- * @param distribution A distribution to add to the query. - ***/ - public void addDistribution(String distribution) - { - if (__distributions != null) - __distributions.append(','); - else - __distributions = new StringBuffer(); - __distributions.append(distribution); - } - - /*** - * Return the NNTP query formatted date (year, month, day in the form - * YYMMDD. - *

- * @return The NNTP query formatted date. - ***/ - public String getDate() - { - return __date; - } - - /*** - * Return the NNTP query formatted time (hour, minutes, seconds in the form - * HHMMSS. - *

- * @return The NNTP query formatted time. - ***/ - public String getTime() - { - return __time; - } - - /*** - * Return whether or not the query date should be treated as GMT. - *

- * @return True if the query date is to be treated as GMT, false if not. - ***/ - public boolean isGMT() - { - return __isGMT; - } - - /*** - * Return the comma separated list of distributions. This may be null - * if there are no distributions. - *

- * @return The list of distributions, which may be null if no distributions - * have been specified. - ***/ - public String getDistributions() - { - return (__distributions == null ? null : __distributions.toString()); - } - - /*** - * Return the comma separated list of newsgroups. This may be null - * if there are no newsgroups - *

- * @return The list of newsgroups, which may be null if no newsgroups - * have been specified. - ***/ - public String getNewsgroups() - { - return (__newsgroups == null ? null : __newsgroups.toString()); - } -} diff --git a/org/apache/commons/net/nntp/NewsgroupInfo.java b/org/apache/commons/net/nntp/NewsgroupInfo.java deleted file mode 100644 index aa48d16..0000000 --- a/org/apache/commons/net/nntp/NewsgroupInfo.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -/*** - * NewsgroupInfo stores information pertaining to a newsgroup returned by - * the NNTP GROUP, LIST, and NEWGROUPS commands, implemented by - * {@link org.apache.commons.net.nntp.NNTPClient#selectNewsgroup selectNewsgroup } - * , - * {@link org.apache.commons.net.nntp.NNTPClient#listNewsgroups listNewsgroups } - * , and - * {@link org.apache.commons.net.nntp.NNTPClient#listNewNewsgroups listNewNewsgroups } - * respectively. - *

- *

- * @author Daniel F. Savarese - * @see NNTPClient - ***/ - -public final class NewsgroupInfo -{ - /*** - * A constant indicating that the posting permission of a newsgroup is - * unknown. For example, the NNTP GROUP command does not return posting - * information, so NewsgroupInfo instances obtained from that command - * willhave an UNKNOWN_POSTING_PERMISSION. - ***/ - public static final int UNKNOWN_POSTING_PERMISSION = 0; - - /*** A constant indicating that a newsgroup is moderated. ***/ - public static final int MODERATED_POSTING_PERMISSION = 1; - - /*** A constant indicating that a newsgroup is public and unmoderated. ***/ - public static final int PERMITTED_POSTING_PERMISSION = 2; - - /*** - * A constant indicating that a newsgroup is closed for general posting. - ***/ - public static final int PROHIBITED_POSTING_PERMISSION = 3; - - private String __newsgroup; - private int __estimatedArticleCount; - private int __firstArticle, __lastArticle; - private int __postingPermission; - - void _setNewsgroup(String newsgroup) - { - __newsgroup = newsgroup; - } - - void _setArticleCount(int count) - { - __estimatedArticleCount = count; - } - - void _setFirstArticle(int first) - { - __firstArticle = first; - } - - void _setLastArticle(int last) - { - __lastArticle = last; - } - - void _setPostingPermission(int permission) - { - __postingPermission = permission; - } - - /*** - * Get the newsgroup name. - *

- * @return The name of the newsgroup. - ***/ - public String getNewsgroup() - { - return __newsgroup; - } - - /*** - * Get the estimated number of articles in the newsgroup. The - * accuracy of this value will depend on the server implementation. - *

- * @return The estimated number of articles in the newsgroup. - ***/ - public int getArticleCount() - { - return __estimatedArticleCount; - } - - /*** - * Get the number of the first article in the newsgroup. - *

- * @return The number of the first article in the newsgroup. - ***/ - public int getFirstArticle() - { - return __firstArticle; - } - - /*** - * Get the number of the last article in the newsgroup. - *

- * @return The number of the last article in the newsgroup. - ***/ - public int getLastArticle() - { - return __lastArticle; - } - - /*** - * Get the posting permission of the newsgroup. This will be one of - * the POSTING_PERMISSION constants. - *

- * @return The posting permission status of the newsgroup. - ***/ - public int getPostingPermission() - { - return __postingPermission; - } - - /* - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(__newsgroup); - buffer.append(' '); - buffer.append(__lastArticle); - buffer.append(' '); - buffer.append(__firstArticle); - buffer.append(' '); - switch(__postingPermission) { - case 1: buffer.append('m'); break; - case 2: buffer.append('y'); break; - case 3: buffer.append('n'); break; - } - return buffer.toString(); -} - */ -} diff --git a/org/apache/commons/net/nntp/SimpleNNTPHeader.java b/org/apache/commons/net/nntp/SimpleNNTPHeader.java deleted file mode 100644 index d18a8cf..0000000 --- a/org/apache/commons/net/nntp/SimpleNNTPHeader.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -/*** - * This class is used to construct the bare minimum - * acceptable header for most news readers. To construct more - * complicated headers you should refer to RFC 822. When the - * Java Mail API is finalized, you will be - * able to use it to compose fully compliant Internet text messages. - *

- * The main purpose of the class is to faciliatate the article posting - * process, by relieving the programmer from having to explicitly format - * an article header. For example: - *

- * writer = client.postArticle();
- * if(writer == null) // failure
- *   return false;
- * header = new SimpleNNTPHeader("foobar@foo.com", "Just testing");
- * header.addNewsgroup("alt.test");
- * header.addHeaderField("Organization", "Foobar, Inc.");
- * writer.write(header.toString());
- * writer.write("This is just a test");
- * writer.close();
- * if(!client.completePendingCommand()) // failure
- *   return false;
- * 
- *

- *

- * @author Daniel F. Savarese - * @see NNTPClient - ***/ - -public class SimpleNNTPHeader -{ - private String __subject, __from; - private StringBuilder __newsgroups; - private StringBuilder __headerFields; - private int __newsgroupCount; - - /*** - * Creates a new SimpleNNTPHeader instance initialized with the given - * from and subject header field values. - *

- * @param from The value of the From: header field. This - * should be the article poster's email address. - * @param subject The value of the Subject: header field. - * This should be the subject of the article. - ***/ - public SimpleNNTPHeader(String from, String subject) - { - __from = from; - __subject = subject; - __newsgroups = new StringBuilder(); - __headerFields = new StringBuilder(); - __newsgroupCount = 0; - } - - /*** - * Adds a newsgroup to the article Newsgroups: field. - *

- * @param newsgroup The newsgroup to add to the article's newsgroup - * distribution list. - ***/ - public void addNewsgroup(String newsgroup) - { - if (__newsgroupCount++ > 0) - __newsgroups.append(','); - __newsgroups.append(newsgroup); - } - - /*** - * Adds an arbitrary header field with the given value to the article - * header. These headers will be written after the From, Newsgroups, - * and Subject fields when the SimpleNNTPHeader is convertered to a string. - * An example use would be: - *

-     * header.addHeaderField("Organization", "Foobar, Inc.");
-     * 
- *

- * @param headerField The header field to add, not including the colon. - * @param value The value of the added header field. - ***/ - public void addHeaderField(String headerField, String value) - { - __headerFields.append(headerField); - __headerFields.append(": "); - __headerFields.append(value); - __headerFields.append('\n'); - } - - - /*** - * Returns the address used in the From: header field. - *

- * @return The from address. - ***/ - public String getFromAddress() - { - return __from; - } - - /*** - * Returns the subject used in the Subject: header field. - *

- * @return The subject. - ***/ - public String getSubject() - { - return __subject; - } - - /*** - * Returns the contents of the Newsgroups: header field. - *

- * @return The comma-separated list of newsgroups to which the article - * is being posted. - ***/ - public String getNewsgroups() - { - return __newsgroups.toString(); - } - - /*** - * Converts the SimpleNNTPHeader to a properly formatted header in - * the form of a String, including the blank line used to separate - * the header from the article body. - *

- * @return The article header in the form of a String. - ***/ - @Override - public String toString() - { - StringBuffer header = new StringBuffer(); - - header.append("From: "); - header.append(__from); - header.append("\nNewsgroups: "); - header.append(__newsgroups.toString()); - header.append("\nSubject: "); - header.append(__subject); - header.append('\n'); - if (__headerFields.length() > 0) - header.append(__headerFields.toString()); - header.append('\n'); - - return header.toString(); - } -} diff --git a/org/apache/commons/net/nntp/Threadable.java b/org/apache/commons/net/nntp/Threadable.java deleted file mode 100644 index 518a9a4..0000000 --- a/org/apache/commons/net/nntp/Threadable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.nntp; - -/** - * A placeholder interface for threadable message objects - * Author: Rory Winston - * - */ -public interface Threadable { - public boolean isDummy(); - public String messageThreadId(); - public String[] messageThreadReferences(); - public String simplifiedSubject(); - public boolean subjectIsReply(); - public void setChild(Threadable child); - public void setNext(Threadable next); - public Threadable makeDummy(); -} diff --git a/org/apache/commons/net/nntp/Threader.java b/org/apache/commons/net/nntp/Threader.java deleted file mode 100644 index d702c67..0000000 --- a/org/apache/commons/net/nntp/Threader.java +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.net.nntp; - -/** - * This is an implementation of a message threading algorithm, as originally devised by Zamie Zawinski. - * See http://www.jwz.org/doc/threading.html for details. - * For his Java implementation, see http://lxr.mozilla.org/mozilla/source/grendel/sources/grendel/view/Threader.java - * - * @author rwinston - * - */ - -import java.util.HashMap; -import java.util.Iterator; - -public class Threader { - private ThreadContainer root; - private HashMap idTable; - private int bogusIdCount = 0; - - /** - * The main threader entry point - The client passes in an array of Threadable objects, and - * the Threader constructs a connected 'graph' of messages - * @param messages - * @return - */ - public Threadable thread(Threadable[] messages) { - if (messages == null) - return null; - - idTable = new HashMap(); - - // walk through each Threadable element - for (int i = 0; i < messages.length; ++i) { - if (!messages[i].isDummy()) - buildContainer(messages[i]); - } - - root = findRootSet(); - idTable.clear(); - idTable = null; - - pruneEmptyContainers(root); - - root.reverseChildren(); - gatherSubjects(); - - if (root.next != null) - throw new RuntimeException("root node has a next:" + root); - - for (ThreadContainer r = root.child; r != null; r = r.next) { - if (r.threadable == null) - r.threadable = r.child.threadable.makeDummy(); - } - - Threadable result = (root.child == null ? null : root.child.threadable); - root.flush(); - root = null; - - return result; - } - - /** - * - * @param threadable - */ - private void buildContainer(Threadable threadable) { - String id = threadable.messageThreadId(); - ThreadContainer container = idTable.get(id); - - // A ThreadContainer exists for this id already. This should be a forward reference, but may - // be a duplicate id, in which case we will need to generate a bogus placeholder id - if (container != null) { - if (container.threadable != null) { // oops! duplicate ids... - id = ""; - container = null; - } else { - // The container just contained a forward reference to this message, so let's - // fill in the threadable field of the container with this message - container.threadable = threadable; - } - } - - // No container exists for that message Id. Create one and insert it into the hash table. - if (container == null) { - container = new ThreadContainer(); - container.threadable = threadable; - idTable.put(id, container); - } - - // Iterate through all of the references and create ThreadContainers for any references that - // don't have them. - ThreadContainer parentRef = null; - { - String[] references = threadable.messageThreadReferences(); - for (int i = 0; i < references.length; ++i) { - String refString = references[i]; - ThreadContainer ref = idTable.get(refString); - - // if this id doesnt have a container, create one - if (ref == null) { - ref = new ThreadContainer(); - idTable.put(refString, ref); - } - - // Link references together in the order they appear in the References: header, - // IF they dont have a have a parent already && - // IF it will not cause a circular reference - if ((parentRef != null) - && (ref.parent == null) - && (parentRef != ref) - && !(parentRef.findChild(ref))) { - // Link ref into the parent's child list - ref.parent = parentRef; - ref.next = parentRef.child; - parentRef.child = ref; - } - parentRef = ref; - } - } - - // parentRef is now set to the container of the last element in the references field. make that - // be the parent of this container, unless doing so causes a circular reference - if (parentRef != null - && (parentRef == container || container.findChild(parentRef))) - parentRef = null; - - // if it has a parent already, its because we saw this message in a References: field, and presumed - // a parent based on the other entries in that field. Now that we have the actual message, we can - // throw away the old parent and use this new one - if (container.parent != null) { - ThreadContainer rest, prev; - - for (prev = null, rest = container.parent.child; - rest != null; - prev = rest, rest = rest.next) { - if (rest == container) - break; - } - - if (rest == null) { - throw new RuntimeException( - "Didnt find " - + container - + " in parent" - + container.parent); - } - - // Unlink this container from the parent's child list - if (prev == null) - container.parent.child = container.next; - else - prev.next = container.next; - - container.next = null; - container.parent = null; - } - - // If we have a parent, link container into the parents child list - if (parentRef != null) { - container.parent = parentRef; - container.next = parentRef.child; - parentRef.child = container; - } - } - - /** - * Find the root set of all existing ThreadContainers - * @return root the ThreadContainer representing the root node - */ - private ThreadContainer findRootSet() { - ThreadContainer root = new ThreadContainer(); - Iterator iter = idTable.keySet().iterator(); - - while (iter.hasNext()) { - Object key = iter.next(); - ThreadContainer c = idTable.get(key); - if (c.parent == null) { - if (c.next != null) - throw new RuntimeException( - "c.next is " + c.next.toString()); - c.next = root.child; - root.child = c; - } - } - return root; - } - - /** - * Delete any empty or dummy ThreadContainers - * @param parent - */ - private void pruneEmptyContainers(ThreadContainer parent) { - ThreadContainer container, prev, next; - for (prev = null, container = parent.child, next = container.next; - container != null; - prev = container, - container = next, - next = (container == null ? null : container.next)) { - - // Is it empty and without any children? If so,delete it - if (container.threadable == null && container.child == null) { - if (prev == null) - parent.child = container.next; - else - prev.next = container.next; - - // Set container to prev so that prev keeps its same value the next time through the loop - container = prev; - } - - // Else if empty, with kids, and (not at root or only one kid) - else if ( - container.threadable == null - && container.child != null - && (container.parent != null - || container.child.next == null)) { - // We have an invalid/expired message with kids. Promote the kids to this level. - ThreadContainer tail; - ThreadContainer kids = container.child; - - // Remove this container and replace with 'kids'. - if (prev == null) - parent.child = kids; - else - prev.next = kids; - - // Make each child's parent be this level's parent -> i.e. promote the children. Make the last child's next point to this container's next - // i.e. splice kids into the list in place of container - for (tail = kids; tail.next != null; tail = tail.next) - tail.parent = container.parent; - - tail.parent = container.parent; - tail.next = container.next; - - // next currently points to the item after the inserted items in the chain - reset that so we process the newly - // promoted items next time round - next = kids; - - // Set container to prev so that prev keeps its same value the next time through the loop - container = prev; - } else if (container.child != null) { - // A real message , with kids - // Iterate over the children - pruneEmptyContainers(container); - } - } - } - - /** - * If any two members of the root set have the same subject, merge them. This is to attempt to accomodate messages without References: headers. - */ - private void gatherSubjects() { - - int count = 0; - - for (ThreadContainer c = root.child; c != null; c = c.next) - count++; - - // TODO verify this will avoid rehashing - HashMap subjectTable = new HashMap((int) (count * 1.2), (float) 0.9); - count = 0; - - for (ThreadContainer c = root.child; c != null; c = c.next) { - Threadable threadable = c.threadable; - - // No threadable? If so, it is a dummy node in the root set. - // Only root set members may be dummies, and they alway have at least 2 kids - // Take the first kid as representative of the subject - if (threadable == null) - threadable = c.child.threadable; - - String subj = threadable.simplifiedSubject(); - - if (subj == null || subj == "") - continue; - - ThreadContainer old = subjectTable.get(subj); - - // Add this container to the table iff: - // - There exists no container with this subject - // - or this is a dummy container and the old one is not - the dummy one is - // more interesting as a root, so put it in the table instead - // - The container in the table has a "Re:" version of this subject, and - // this container has a non-"Re:" version of this subject. The non-"Re:" version - // is the more interesting of the two. - if (old == null - || (c.threadable == null && old.threadable != null) - || (old.threadable != null - && old.threadable.subjectIsReply() - && c.threadable != null - && !c.threadable.subjectIsReply())) { - subjectTable.put(subj, c); - count++; - } - } - - // If the table is empty, we're done - if (count == 0) - return; - - // subjectTable is now populated with one entry for each subject which occurs in the - // root set. Iterate over the root set, and gather together the difference. - ThreadContainer prev, c, rest; - for (prev = null, c = root.child, rest = c.next; - c != null; - prev = c, c = rest, rest = (rest == null ? null : rest.next)) { - Threadable threadable = c.threadable; - - // is it a dummy node? - if (threadable == null) - threadable = c.child.threadable; - - String subj = threadable.simplifiedSubject(); - - // Dont thread together all subjectless messages - if (subj == null || subj == "") - continue; - - ThreadContainer old = subjectTable.get(subj); - - if (old == c) // That's us - continue; - - // We have now found another container in the root set with the same subject - // Remove the "second" message from the root set - if (prev == null) - root.child = c.next; - else - prev.next = c.next; - c.next = null; - - if (old.threadable == null && c.threadable == null) { - // both dummies - merge them - ThreadContainer tail; - for (tail = old.child; - tail != null && tail.next != null; - tail = tail.next); - - tail.next = c.child; - - for (tail = c.child; tail != null; tail = tail.next) - tail.parent = old; - - c.child = null; - } else if ( - old.threadable == null - || (c.threadable != null - && c.threadable.subjectIsReply() - && !old.threadable.subjectIsReply())) { - // Else if old is empty, or c has "Re:" and old does not ==> make this message a child of old - c.parent = old; - c.next = old.child; - old.child = c; - } else { - // else make the old and new messages be children of a new dummy container. - // We create a new container object for old.msg and empty the old container - ThreadContainer newc = new ThreadContainer(); - newc.threadable = old.threadable; - newc.child = old.child; - - for (ThreadContainer tail = newc.child; - tail != null; - tail = tail.next) - tail.parent = newc; - - old.threadable = null; - old.child = null; - - c.parent = old; - newc.parent = old; - - // Old is now a dummy- give it 2 kids , c and newc - old.child = c; - c.next = newc; - } - // We've done a merge, so keep the same prev - c = prev; - } - - subjectTable.clear(); - subjectTable = null; - - } -} - -/** - * A placeholder utility class, used for constructing a tree of Threadables - * Originall implementation by Jamie Zawinski. - * See the Grendel source for more details here - * Threadable objects - * @author Rory Winston - */ -class ThreadContainer { - Threadable threadable; - ThreadContainer parent; - ThreadContainer prev; - ThreadContainer next; - ThreadContainer child; - - /** - * - * @param container - * @return true if child is under self's tree. Detects circular references - */ - boolean findChild(ThreadContainer target) { - if (child == null) - return false; - - else if (child == target) - return true; - else - return child.findChild(target); - } - - // Copy the ThreadContainer tree structure down into the underlying Threadable objects - // (Make the Threadable tree look like the ThreadContainer tree) - void flush() { - if (parent != null && threadable == null) - throw new RuntimeException("no threadable in " + this.toString()); - - parent = null; - - if (threadable != null) - threadable.setChild(child == null ? null : child.threadable); - - if (child != null) { - child.flush(); - child = null; - } - - if (threadable != null) - threadable.setNext(next == null ? null : next.threadable); - - if (next != null) { - next.flush(); - next = null; - } - - threadable = null; - } - - /** - * Reverse the entire set of children - * - */ - void reverseChildren() { - if (child != null) { - ThreadContainer kid, prev, rest; - for (prev = null, kid = child, rest = kid.next; - kid != null; - prev = kid, - kid = rest, - rest = (rest == null ? null : rest.next)) - kid.next = prev; - - child = prev; - - // Do it for the kids - for (kid = child; kid != null; kid = kid.next) - kid.reverseChildren(); - } - } -} diff --git a/org/apache/commons/net/ntp/NTPUDPClient.java b/org/apache/commons/net/ntp/NTPUDPClient.java deleted file mode 100644 index e1dcb57..0000000 --- a/org/apache/commons/net/ntp/NTPUDPClient.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; - -import org.apache.commons.net.DatagramSocketClient; - -/*** - * The NTPUDPClient class is a UDP implementation of a client for the - * Network Time Protocol (NTP) described in RFC 1305 as well as the - * Simple Network Time Protocol (SNTP) in RFC-2030. To use the class, - * merely open a local datagram socket with open - * and call getTime to retrieve the time. Then call - * close - * to close the connection properly. - * Successive calls to getTime are permitted - * without re-establishing a connection. That is because UDP is a - * connectionless protocol and the Network Time Protocol is stateless. - * - * @author Jason Mathews, MITRE Corp - * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ - ***/ - -public final class NTPUDPClient extends DatagramSocketClient -{ - /*** The default NTP port. It is set to 123 according to RFC 1305. ***/ - public static final int DEFAULT_PORT = 123; - - private int _version = NtpV3Packet.VERSION_3; - - /*** - * Retrieves the time information from the specified server and port and - * returns it. The time is the number of miliiseconds since - * 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. - * This method reads the raw NTP packet and constructs a TimeInfo - * object that allows access to all the fields of the NTP message header. - *

- * @param host The address of the server. - * @param port The port of the service. - * @return The time value retrieved from the server. - * @exception IOException If an error occurs while retrieving the time. - ***/ - public TimeInfo getTime(InetAddress host, int port) throws IOException - { - // if not connected then open to next available UDP port - if (!isOpen()) - { - open(); - } - - NtpV3Packet message = new NtpV3Impl(); - message.setMode(NtpV3Packet.MODE_CLIENT); - message.setVersion(_version); - DatagramPacket sendPacket = message.getDatagramPacket(); - sendPacket.setAddress(host); - sendPacket.setPort(port); - - NtpV3Packet recMessage = new NtpV3Impl(); - DatagramPacket receivePacket = recMessage.getDatagramPacket(); - - /* - * Must minimize the time between getting the current time, - * timestamping the packet, and sending it out which - * introduces an error in the delay time. - * No extraneous logging and initializations here !!! - */ - TimeStamp now = TimeStamp.getCurrentTime(); - - // Note that if you do not set the transmit time field then originating time - // in server response is all 0's which is "Thu Feb 07 01:28:16 EST 2036". - message.setTransmitTime(now); - - _socket_.send(sendPacket); - _socket_.receive(receivePacket); - - long returnTime = System.currentTimeMillis(); - // create TimeInfo message container but don't pre-compute the details yet - TimeInfo info = new TimeInfo(recMessage, returnTime, false); - - return info; - } - - /*** - * Retrieves the time information from the specified server on the - * default NTP port and returns it. The time is the number of miliiseconds - * since 00:00 (midnight) 1 January 1900 UTC, as specified by RFC 1305. - * This method reads the raw NTP packet and constructs a TimeInfo - * object that allows access to all the fields of the NTP message header. - *

- * @param host The address of the server. - * @return The time value retrieved from the server. - * @exception IOException If an error occurs while retrieving the time. - ***/ - public TimeInfo getTime(InetAddress host) throws IOException - { - return getTime(host, NtpV3Packet.NTP_PORT); - } - - /*** - * Returns the NTP protocol version number that client sets on request packet - * that is sent to remote host (e.g. 3=NTP v3, 4=NTP v4, etc.) - * - * @return the NTP protocol version number that client sets on request packet. - * @see #setVersion(int) - ***/ - public int getVersion() - { - return _version; - } - - /*** - * Sets the NTP protocol version number that client sets on request packet - * communicate with remote host. - * - * @param version the NTP protocol version number - ***/ - public void setVersion(int version) - { - _version = version; - } - -} diff --git a/org/apache/commons/net/ntp/NtpUtils.java b/org/apache/commons/net/ntp/NtpUtils.java deleted file mode 100644 index ca1fb41..0000000 --- a/org/apache/commons/net/ntp/NtpUtils.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/*** - * Common NtpUtils Helper class. - * - * @author Jason Mathews, MITRE Corp - * - * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ - */ -public final class NtpUtils { - - /*** - * Returns 32-bit integer address to IPv4 address string "%d.%d.%d.%d" format. - * - * @param address the 32-bit address - * @return the raw IP address in a string format. - */ - public static String getHostAddress(int address) - { - return ((address >>> 24) & 0xFF) + "." + - ((address >>> 16) & 0xFF) + "." + - ((address >>> 8) & 0xFF) + "." + - ((address >>> 0) & 0xFF); - } - - /*** - * Returns NTP packet reference identifier as IP address. - * - * @param packet NTP packet - * @return the packet reference id (as IP address) in "%d.%d.%d.%d" format. - */ - public static String getRefAddress(NtpV3Packet packet) - { - int address = (packet == null) ? 0 : packet.getReferenceId(); - return getHostAddress(address); - } - - /*** - * Get refId as reference clock string (e.g. GPS, WWV, LCL). If string is - * invalid (non-ASCII character) then returns empty string "". - * For details refer to the Comprehensive - * List of Clock Drivers. - * - * @param message - * @return reference clock string if primary NTP server - */ - public static String getReferenceClock(NtpV3Packet message) { - if (message == null) - return ""; - int refId = message.getReferenceId(); - if (refId == 0) - return ""; - StringBuffer buf = new StringBuffer(4); - // start at highest-order byte (0x4c434c00 -> LCL) - for (int shiftBits = 24; shiftBits >= 0; shiftBits -= 8) - { - char c = (char) ((refId >>> shiftBits) & 0xff); - if (c == 0) break; // 0-terminated ASCII string - if (!Character.isLetterOrDigit(c)) - return ""; - buf.append(c); - } - return buf.toString(); - } - - /*** - * Return human-readable name of message mode type (RFC 1305). - * - * @param mode - * @return mode name - */ - public static String getModeName(int mode) - { - switch (mode) { - case NtpV3Packet.MODE_RESERVED: - return "Reserved"; - case NtpV3Packet.MODE_SYMMETRIC_ACTIVE: - return "Symmetric Active"; - case NtpV3Packet.MODE_SYMMETRIC_PASSIVE: - return "Symmetric Passive"; - case NtpV3Packet.MODE_CLIENT: - return "Client"; - case NtpV3Packet.MODE_SERVER: - return "Server"; - case NtpV3Packet.MODE_BROADCAST: - return "Broadcast"; - case NtpV3Packet.MODE_CONTROL_MESSAGE: - return "Control"; - case NtpV3Packet.MODE_PRIVATE: - return "Private"; - default: - return "Unknown"; - } - } - -} diff --git a/org/apache/commons/net/ntp/NtpV3Impl.java b/org/apache/commons/net/ntp/NtpV3Impl.java deleted file mode 100644 index 4a8569a..0000000 --- a/org/apache/commons/net/ntp/NtpV3Impl.java +++ /dev/null @@ -1,583 +0,0 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.net.DatagramPacket; - -/*** - * Implementation of NtpV3Packet with methods converting Java objects to/from - * the Network Time Protocol (NTP) data message header format described in RFC-1305. - * - * @author Naz Irizarry, MITRE Corp - * @author Jason Mathews, MITRE Corp - * - * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ - */ -public class NtpV3Impl implements NtpV3Packet -{ - - private static final int MODE_INDEX = 0; - private static final int MODE_SHIFT = 0; - - private static final int VERSION_INDEX = 0; - private static final int VERSION_SHIFT = 3; - - private static final int LI_INDEX = 0; - private static final int LI_SHIFT = 6; - - private static final int STRATUM_INDEX = 1; - private static final int POLL_INDEX = 2; - private static final int PRECISION_INDEX = 3; - - private static final int ROOT_DELAY_INDEX = 4; - private static final int ROOT_DISPERSION_INDEX = 8; - private static final int REFERENCE_ID_INDEX = 12; - - private static final int REFERENCE_TIMESTAMP_INDEX = 16; - private static final int ORIGINATE_TIMESTAMP_INDEX = 24; - private static final int RECEIVE_TIMESTAMP_INDEX = 32; - private static final int TRANSMIT_TIMESTAMP_INDEX = 40; - - private static final int KEY_IDENTIFIER_INDEX = 48; - private static final int MESSAGE_DIGEST = 54; /* len 16 bytes */ - - private byte[] buf = new byte[48]; - - private volatile DatagramPacket dp; - - /** Creates a new instance of NtpV3Impl */ - public NtpV3Impl() - { - } - - /*** - * Returns mode as defined in RFC-1305 which is a 3-bit integer - * whose value is indicated by the MODE_xxx parameters. - * - * @return mode as defined in RFC-1305. - */ - public int getMode() - { - return (ui(buf[MODE_INDEX]) >> MODE_SHIFT) & 0x7; - } - - /*** - * Return human-readable name of message mode type as described in - * RFC 1305. - * @return mode name as string. - */ - public String getModeName() - { - return NtpUtils.getModeName(getMode()); - } - - /*** - * Set mode as defined in RFC-1305. - * @param mode - */ - public void setMode(int mode) - { - buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7); - } - - /*** - * Returns leap indicator as defined in RFC-1305 which is a two-bit code: - * 0=no warning - * 1=last minute has 61 seconds - * 2=last minute has 59 seconds - * 3=alarm condition (clock not synchronized) - * - * @return leap indicator as defined in RFC-1305. - */ - public int getLeapIndicator() - { - return (ui(buf[LI_INDEX]) >> LI_SHIFT) & 0x3; - } - - /*** - * Set leap indicator as defined in RFC-1305. - * @param li leap indicator. - */ - public void setLeapIndicator(int li) - { - buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | ((li & 0x3) << LI_SHIFT)); - } - - /*** - * Returns poll interval as defined in RFC-1305, which is an eight-bit - * signed integer indicating the maximum interval between successive - * messages, in seconds to the nearest power of two (e.g. value of six - * indicates an interval of 64 seconds. The values that can appear in - * this field range from NTP_MINPOLL to NTP_MAXPOLL inclusive. - * - * @return poll interval as defined in RFC-1305. - */ - public int getPoll() - { - return buf[POLL_INDEX]; - } - - /*** - * Set poll interval as defined in RFC-1305. - * - * @param poll poll interval. - */ - public void setPoll(int poll) - { - buf[POLL_INDEX] = (byte) (poll & 0xFF); - } - - /*** - * Returns precision as defined in RFC-1305 encoded as an 8-bit signed - * integer (seconds to nearest power of two). - * Values normally range from -6 to -20. - * - * @return precision as defined in RFC-1305. - */ - public int getPrecision() - { - return buf[PRECISION_INDEX]; - } - - /*** - * Set precision as defined in RFC-1305. - * @param precision - */ - public void setPrecision(int precision) - { - buf[PRECISION_INDEX] = (byte) (precision & 0xFF); - } - - /*** - * Returns NTP version number as defined in RFC-1305. - * - * @return NTP version number. - */ - public int getVersion() - { - return (ui(buf[VERSION_INDEX]) >> VERSION_SHIFT) & 0x7; - } - - /*** - * Set NTP version as defined in RFC-1305. - * - * @param version NTP version. - */ - public void setVersion(int version) - { - buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | ((version & 0x7) << VERSION_SHIFT)); - } - - /*** - * Returns Stratum as defined in RFC-1305, which indicates the stratum level - * of the local clock, with values defined as follows: 0=unspecified, - * 1=primary ref clock, and all others a secondary reference (via NTP). - * - * @return Stratum level as defined in RFC-1305. - */ - public int getStratum() - { - return ui(buf[STRATUM_INDEX]); - } - - /*** - * Set stratum level as defined in RFC-1305. - * - * @param stratum stratum level. - */ - public void setStratum(int stratum) - { - buf[STRATUM_INDEX] = (byte) (stratum & 0xFF); - } - - /*** - * Return root delay as defined in RFC-1305, which is the total roundtrip delay - * to the primary reference source, in seconds. Values can take positive and - * negative values, depending on clock precision and skew. - * - * @return root delay as defined in RFC-1305. - */ - public int getRootDelay() - { - return getInt(ROOT_DELAY_INDEX); - } - - /*** - * Return root delay as defined in RFC-1305 in milliseconds, which is - * the total roundtrip delay to the primary reference source, in - * seconds. Values can take positive and negative values, depending - * on clock precision and skew. - * - * @return root delay in milliseconds - */ - public double getRootDelayInMillisDouble() - { - double l = getRootDelay(); - return l / 65.536; - } - - /*** - * Returns root dispersion as defined in RFC-1305. - * @return root dispersion. - */ - public int getRootDispersion() - { - return getInt(ROOT_DISPERSION_INDEX); - } - - /*** - * Returns root dispersion (as defined in RFC-1305) in milliseconds. - * - * @return root dispersion in milliseconds - */ - public long getRootDispersionInMillis() - { - long l = getRootDispersion(); - return (l * 1000) / 65536L; - } - - /*** - * Returns root dispersion (as defined in RFC-1305) in milliseconds - * as double precision value. - * - * @return root dispersion in milliseconds - */ - public double getRootDispersionInMillisDouble() - { - double l = getRootDispersion(); - return l / 65.536; - } - - /*** - * Set reference clock identifier field with 32-bit unsigned integer value. - * See RFC-1305 for description. - * - * @param refId reference clock identifier. - */ - public void setReferenceId(int refId) - { - for (int i = 3; i >= 0; i--) { - buf[REFERENCE_ID_INDEX + i] = (byte) (refId & 0xff); - refId >>>= 8; // shift right one-byte - } - } - - /*** - * Returns the reference id as defined in RFC-1305, which is - * a 32-bit integer whose value is dependent on several criteria. - * - * @return the reference id as defined in RFC-1305. - */ - public int getReferenceId() - { - return getInt(REFERENCE_ID_INDEX); - } - - /*** - * Returns the reference id string. String cannot be null but - * value is dependent on the version of the NTP spec supported - * and stratum level. Value can be an empty string, clock type string, - * IP address, or a hex string. - * - * @return the reference id string. - */ - public String getReferenceIdString() - { - int version = getVersion(); - int stratum = getStratum(); - if (version == VERSION_3 || version == VERSION_4) { - if (stratum == 0 || stratum == 1) { - return idAsString(); // 4-character ASCII string (e.g. GPS, USNO) - } - // in NTPv4 servers this is latest transmit timestamp of ref source - if (version == VERSION_4) - return idAsHex(); - } - - // Stratum 2 and higher this is a four-octet IPv4 address - // of the primary reference host. - if (stratum >= 2) { - return idAsIPAddress(); - } - return idAsHex(); - } - - /*** - * Returns Reference id as dotted IP address. - * @return refId as IP address string. - */ - private String idAsIPAddress() - { - return ui(buf[REFERENCE_ID_INDEX]) + "." + - ui(buf[REFERENCE_ID_INDEX + 1]) + "." + - ui(buf[REFERENCE_ID_INDEX + 2]) + "." + - ui(buf[REFERENCE_ID_INDEX + 3]); - } - - private String idAsString() - { - StringBuilder id = new StringBuilder(); - for (int i = 0; i <= 3; i++) { - char c = (char) buf[REFERENCE_ID_INDEX + i]; - if (c == 0) break; // 0-terminated string - id.append(c); - } - return id.toString(); - } - - private String idAsHex() - { - return Integer.toHexString(getReferenceId()); - } - - /*** - * Returns the transmit timestamp as defined in RFC-1305. - * - * @return the transmit timestamp as defined in RFC-1305. - * Never returns a null object. - */ - public TimeStamp getTransmitTimeStamp() - { - return getTimestamp(TRANSMIT_TIMESTAMP_INDEX); - } - - /*** - * Set transmit time with NTP timestamp. - * If ts is null then zero time is used. - * - * @param ts NTP timestamp - */ - public void setTransmitTime(TimeStamp ts) - { - setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts); - } - - /*** - * Set originate timestamp given NTP TimeStamp object. - * If ts is null then zero time is used. - * - * @param ts NTP timestamp - */ - public void setOriginateTimeStamp(TimeStamp ts) - { - setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts); - } - - /*** - * Returns the originate time as defined in RFC-1305. - * - * @return the originate time. - * Never returns null. - */ - public TimeStamp getOriginateTimeStamp() - { - return getTimestamp(ORIGINATE_TIMESTAMP_INDEX); - } - - /*** - * Returns the reference time as defined in RFC-1305. - * - * @return the reference time as TimeStamp object. - * Never returns null. - */ - public TimeStamp getReferenceTimeStamp() - { - return getTimestamp(REFERENCE_TIMESTAMP_INDEX); - } - - /*** - * Set Reference time with NTP timestamp. If ts is null - * then zero time is used. - * - * @param ts NTP timestamp - */ - public void setReferenceTime(TimeStamp ts) - { - setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts); - } - - /*** - * Returns receive timestamp as defined in RFC-1305. - * - * @return the receive time. - * Never returns null. - */ - public TimeStamp getReceiveTimeStamp() - { - return getTimestamp(RECEIVE_TIMESTAMP_INDEX); - } - - /*** - * Set receive timestamp given NTP TimeStamp object. - * If ts is null then zero time is used. - * - * @param ts timestamp - */ - public void setReceiveTimeStamp(TimeStamp ts) - { - setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts); - } - - /*** - * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) - * correspond to the protocol used to obtain the timing information. - * - * @return packet type string identifier which in this case is "NTP". - */ - public String getType() - { - return "NTP"; - } - - /*** - * @return 4 bytes as 32-bit int - */ - private int getInt(int index) - { - int i = ui(buf[index]) << 24 | - ui(buf[index + 1]) << 16 | - ui(buf[index + 2]) << 8 | - ui(buf[index + 3]); - - return i; - } - - /*** - * Get NTP Timestamp at specified starting index. - * - * @param index index into data array - * @return TimeStamp object for 64 bits starting at index - */ - private TimeStamp getTimestamp(int index) - { - return new TimeStamp(getLong(index)); - } - - /*** - * Get Long value represented by bits starting at specified index. - * - * @return 8 bytes as 64-bit long - */ - private long getLong(int index) - { - long i = ul(buf[index]) << 56 | - ul(buf[index + 1]) << 48 | - ul(buf[index + 2]) << 40 | - ul(buf[index + 3]) << 32 | - ul(buf[index + 4]) << 24 | - ul(buf[index + 5]) << 16 | - ul(buf[index + 6]) << 8 | - ul(buf[index + 7]); - return i; - } - - /*** - * Sets the NTP timestamp at the given array index. - * - * @param index index into the byte array. - * @param t TimeStamp. - */ - private void setTimestamp(int index, TimeStamp t) - { - long ntpTime = (t == null) ? 0 : t.ntpValue(); - // copy 64-bits from Long value into 8 x 8-bit bytes of array - // one byte at a time shifting 8-bits for each position. - for (int i = 7; i >= 0; i--) { - buf[index + i] = (byte) (ntpTime & 0xFF); - ntpTime >>>= 8; // shift to next byte - } - // buf[index] |= 0x80; // only set if 1900 baseline.... - } - - /*** - * Returns the datagram packet with the NTP details already filled in. - * - * @return a datagram packet. - */ - public synchronized DatagramPacket getDatagramPacket() - { - if (dp == null) { - dp = new DatagramPacket(buf, buf.length); - dp.setPort(NTP_PORT); - } - return dp; - } - - /*** - * Set the contents of this object from source datagram packet. - * - * @param srcDp source DatagramPacket to copy contents from. - */ - public void setDatagramPacket(DatagramPacket srcDp) - { - byte[] incomingBuf = srcDp.getData(); - int len = srcDp.getLength(); - if (len > buf.length) - len = buf.length; - - System.arraycopy(incomingBuf, 0, buf, 0, len); - } - - /*** - * Convert byte to unsigned integer. - * Java only has signed types so we have to do - * more work to get unsigned ops. - * - * @param b - * @return unsigned int value of byte - */ - protected final static int ui(byte b) - { - int i = b & 0xFF; - return i; - } - - /*** - * Convert byte to unsigned long. - * Java only has signed types so we have to do - * more work to get unsigned ops - * - * @param b - * @return unsigned long value of byte - */ - protected final static long ul(byte b) - { - long i = b & 0xFF; - return i; - } - - /*** - * Returns details of NTP packet as a string. - * - * @return details of NTP packet as a string. - */ - @Override - public String toString() - { - return "[" + - "version:" + getVersion() + - ", mode:" + getMode() + - ", poll:" + getPoll() + - ", precision:" + getPrecision() + - ", delay:" + getRootDelay() + - ", dispersion(ms):" + getRootDispersionInMillisDouble() + - ", id:" + getReferenceIdString() + - ", xmitTime:" + getTransmitTimeStamp().toDateString() + - " ]"; - } - -} diff --git a/org/apache/commons/net/ntp/NtpV3Packet.java b/org/apache/commons/net/ntp/NtpV3Packet.java deleted file mode 100644 index 52c828b..0000000 --- a/org/apache/commons/net/ntp/NtpV3Packet.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.net.DatagramPacket; - -/** - * Interface for a NtpV3Packet with get/set methods corresponding to the fields - * in the NTP Data Message Header described in RFC 1305. - * - * @author Naz Irizarry, MITRE Corp - * @author Jason Mathews, MITRE Corp - * @version $Revision: 489397 $ $Date: 2006-12-21 16:28:51 +0000 (Thu, 21 Dec 2006) $ - */ -public interface NtpV3Packet -{ - - /** - * Standard NTP UDP port - */ - public static final int NTP_PORT = 123; - - public static final int LI_NO_WARNING = 0; - public static final int LI_LAST_MINUTE_HAS_61_SECONDS = 1; - public static final int LI_LAST_MINUTE_HAS_59_SECONDS = 2; - public static final int LI_ALARM_CONDITION = 3; - - /* mode options */ - public static final int MODE_RESERVED = 0; - public static final int MODE_SYMMETRIC_ACTIVE = 1; - public static final int MODE_SYMMETRIC_PASSIVE = 2; - public static final int MODE_CLIENT = 3; - public static final int MODE_SERVER = 4; - public static final int MODE_BROADCAST = 5; - public static final int MODE_CONTROL_MESSAGE = 6; - public static final int MODE_PRIVATE = 7; - - public static final int NTP_MINPOLL = 4; // 16 seconds - public static final int NTP_MAXPOLL = 14; // 16284 seconds - - public static final int NTP_MINCLOCK = 1; - public static final int NTP_MAXCLOCK = 10; - - public static final int VERSION_3 = 3; - public static final int VERSION_4 = 4; - - /* possible getType values such that other time-related protocols can - * have its information represented as NTP packets - */ - public static final String TYPE_NTP = "NTP"; // RFC-1305/2030 - public static final String TYPE_ICMP = "ICMP"; // RFC-792 - public static final String TYPE_TIME = "TIME"; // RFC-868 - public static final String TYPE_DAYTIME = "DAYTIME"; // RFC-867 - - /** - * @return a datagram packet with the NTP parts already filled in - */ - public DatagramPacket getDatagramPacket(); - - /** - * Set the contents of this object from the datagram packet - */ - public void setDatagramPacket(DatagramPacket dp); - - /** - * @return leap indicator as defined in RFC-1305 - */ - public int getLeapIndicator(); - - /** - * Set leap indicator. - * @param li - leap indicator code - */ - public void setLeapIndicator(int li); - - /** - * @return mode as defined in RFC-1305 - */ - public int getMode(); - - /** - * @return mode as human readable string; e.g. 3=Client - */ - public String getModeName(); - - /** - * Set mode as defined in RFC-1305 - */ - public void setMode(int mode); - - /** - * @return poll interval as defined in RFC-1305. - * Field range between NTP_MINPOLL and NTP_MAXPOLL. - */ - public int getPoll(); - - /** - * Set poll interval as defined in RFC-1305. - * Field range between NTP_MINPOLL and NTP_MAXPOLL. - */ - public void setPoll(int poll); - - /** - * @return precision as defined in RFC-1305 - */ - public int getPrecision(); - - /** - * @return root delay as defined in RFC-1305 - */ - public int getRootDelay(); - - /** - * @return root delay in milliseconds - */ - public double getRootDelayInMillisDouble(); - - /** - * @return root dispersion as defined in RFC-1305 - */ - public int getRootDispersion(); - - /** - * @return root dispersion in milliseconds - */ - public long getRootDispersionInMillis(); - - /** - * @return root dispersion in milliseconds - */ - public double getRootDispersionInMillisDouble(); - - /** - * @return version as defined in RFC-1305 - */ - public int getVersion(); - - /** - * Set version as defined in RFC-1305 - */ - public void setVersion(int mode); - - /** - * @return stratum as defined in RFC-1305 - */ - public int getStratum(); - - /** - * Set stratum as defined in RFC-1305 - */ - public void setStratum(int stratum); - - /** - * @return the reference id string - */ - public String getReferenceIdString(); - - /** - * @return the reference id (32-bit code) as defined in RFC-1305 - */ - public int getReferenceId(); - - /** - * Set reference clock identifier field. - * @param refId - */ - public void setReferenceId(int refId); - - /** - * @return the transmit timestamp as defined in RFC-1305 - */ - public TimeStamp getTransmitTimeStamp(); - - /** - * @return the reference time as defined in RFC-1305 - */ - public TimeStamp getReferenceTimeStamp(); - - /** - * @return the originate time as defined in RFC-1305 - */ - public TimeStamp getOriginateTimeStamp(); - - /** - * @return the receive time as defined in RFC-1305 - */ - public TimeStamp getReceiveTimeStamp(); - - /** - * Set the transmit timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - public void setTransmitTime(TimeStamp ts); - - /** - * Set the reference timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - public void setReferenceTime(TimeStamp ts); - - /** - * Set originate timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - public void setOriginateTimeStamp(TimeStamp ts); - - /** - * Set receive timestamp given NTP TimeStamp object. - * @param ts - timestamp - */ - public void setReceiveTimeStamp(TimeStamp ts); - - /** - * Return type of time packet. The values (e.g. NTP, TIME, ICMP, ...) - * correspond to the protocol used to obtain the timing information. - * - * @return packet type string identifier - */ - public String getType(); - -} diff --git a/org/apache/commons/net/ntp/TimeInfo.java b/org/apache/commons/net/ntp/TimeInfo.java deleted file mode 100644 index 4ef17fd..0000000 --- a/org/apache/commons/net/ntp/TimeInfo.java +++ /dev/null @@ -1,295 +0,0 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.util.ArrayList; -import java.util.List; - -/** - * Wrapper class to network time packet messages (NTP, etc) that computes - * related timing info and stats. - * - * @author Jason Mathews, MITRE Corp - * - * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ - */ -public class TimeInfo { - - private NtpV3Packet _message; - private List _comments; - private Long _delay; - private Long _offset; - - /** - * time at which time message packet was received by local machine - */ - private long _returnTime; - - /** - * flag indicating that the TimeInfo details was processed and delay/offset were computed - */ - private boolean _detailsComputed; - - /** - * Create TimeInfo object with raw packet message and destination time received. - * - * @param message NTP message packet - * @param returnTime destination receive time - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(NtpV3Packet message, long returnTime) { - this(message, returnTime, null, true); - } - - /** - * Create TimeInfo object with raw packet message and destination time received. - * - * @param message NTP message packet - * @param returnTime destination receive time - * @param comments List of errors/warnings identified during processing - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(NtpV3Packet message, long returnTime, List comments) - { - this(message, returnTime, comments, true); - } - - /** - * Create TimeInfo object with raw packet message and destination time received. - * Auto-computes details if computeDetails flag set otherwise this is delayed - * until computeDetails() is called. Delayed computation is for fast - * intialization when sub-millisecond timing is needed. - * - * @param msgPacket NTP message packet - * @param returnTime destination receive time - * @param doComputeDetails flag to pre-compute delay/offset values - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(NtpV3Packet msgPacket, long returnTime, boolean doComputeDetails) - { - this(msgPacket, returnTime, null, doComputeDetails); - } - - /** - * Create TimeInfo object with raw packet message and destination time received. - * Auto-computes details if computeDetails flag set otherwise this is delayed - * until computeDetails() is called. Delayed computation is for fast - * intialization when sub-millisecond timing is needed. - * - * @param message NTP message packet - * @param returnTime destination receive time - * @param comments list of comments used to store errors/warnings with message - * @param doComputeDetails flag to pre-compute delay/offset values - * @throws IllegalArgumentException if message is null - */ - public TimeInfo(NtpV3Packet message, long returnTime, List comments, - boolean doComputeDetails) - { - if (message == null) - throw new IllegalArgumentException("message cannot be null"); - this._returnTime = returnTime; - this._message = message; - this._comments = comments; - if (doComputeDetails) - computeDetails(); - } - - /** - * Add comment (error/warning) to list of comments associated - * with processing of NTP parameters. If comment list not create - * then one will be created. - * - * @param comment - */ - public void addComment(String comment) - { - if (_comments == null) { - _comments = new ArrayList(); - } - _comments.add(comment); - } - - /** - * Compute and validate details of the NTP message packet. Computed - * fields include the offset and delay. - */ - public void computeDetails() - { - if (_detailsComputed) { - return; // details already computed - do nothing - } - _detailsComputed = true; - if (_comments == null) { - _comments = new ArrayList(); - } - - TimeStamp origNtpTime = _message.getOriginateTimeStamp(); - long origTime = origNtpTime.getTime(); - - // Receive Time is time request received by server (t2) - TimeStamp rcvNtpTime = _message.getReceiveTimeStamp(); - long rcvTime = rcvNtpTime.getTime(); - - // Transmit time is time reply sent by server (t3) - TimeStamp xmitNtpTime = _message.getTransmitTimeStamp(); - long xmitTime = xmitNtpTime.getTime(); - - /* - * Round-trip network delay and local clock offset (or time drift) is calculated - * according to this standard NTP equation: - * - * LocalClockOffset = ((ReceiveTimestamp - OriginateTimestamp) + - * (TransmitTimestamp - DestinationTimestamp)) / 2 - * - * equations from RFC-1305 (NTPv3) - * roundtrip delay = (t4 - t1) - (t3 - t2) - * local clock offset = ((t2 - t1) + (t3 - t4)) / 2 - * - * It takes into account network delays and assumes that they are symmetrical. - * - * Note the typo in SNTP RFCs 1769/2030 which state that the delay - * is (T4 - T1) - (T2 - T3) with the "T2" and "T3" switched. - */ - if (origNtpTime.ntpValue() == 0) - { - // without originate time cannot determine when packet went out - // might be via a broadcast NTP packet... - if (xmitNtpTime.ntpValue() != 0) - { - _offset = Long.valueOf(xmitTime - _returnTime); - _comments.add("Error: zero orig time -- cannot compute delay"); - } else - _comments.add("Error: zero orig time -- cannot compute delay/offset"); - } else if (rcvNtpTime.ntpValue() == 0 || xmitNtpTime.ntpValue() == 0) - { - _comments.add("Warning: zero rcvNtpTime or xmitNtpTime"); - // assert destTime >= origTime since network delay cannot be negative - if (origTime > _returnTime) - _comments.add("Error: OrigTime > DestRcvTime"); - else - { - // without receive or xmit time cannot figure out processing time - // so delay is simply the network travel time - _delay = Long.valueOf(_returnTime - origTime); - } - // TODO: is offset still valid if rcvNtpTime=0 || xmitNtpTime=0 ??? - // Could always hash origNtpTime (sendTime) but if host doesn't set it - // then it's an malformed ntp host anyway and we don't care? - // If server is in broadcast mode then we never send out a query in first place... - if (rcvNtpTime.ntpValue() != 0) - { - // xmitTime is 0 just use rcv time - _offset = Long.valueOf(rcvTime - origTime); - } else if (xmitNtpTime.ntpValue() != 0) - { - // rcvTime is 0 just use xmitTime time - _offset = Long.valueOf(xmitTime - _returnTime); - } - } else - { - long delayValue = _returnTime - origTime; - // assert xmitTime >= rcvTime: difference typically < 1ms - if (xmitTime < rcvTime) - { - // server cannot send out a packet before receiving it... - _comments.add("Error: xmitTime < rcvTime"); // time-travel not allowed - } else - { - // subtract processing time from round-trip network delay - long delta = xmitTime - rcvTime; - // in normal cases the processing delta is less than - // the total roundtrip network travel time. - if (delta <= delayValue) - { - delayValue -= delta; // delay = (t4 - t1) - (t3 - t2) - } else - { - // if delta - delayValue == 1 ms then it's a round-off error - // e.g. delay=3ms, processing=4ms - if (delta - delayValue == 1) - { - // delayValue == 0 -> local clock saw no tick change but destination clock did - if (delayValue != 0) - { - _comments.add("Info: processing time > total network time by 1 ms -> assume zero delay"); - delayValue = 0; - } - } else - _comments.add("Warning: processing time > total network time"); - } - } - _delay = Long.valueOf(delayValue); - if (origTime > _returnTime) // assert destTime >= origTime - _comments.add("Error: OrigTime > DestRcvTime"); - - _offset = Long.valueOf(((rcvTime - origTime) + (xmitTime - _returnTime)) / 2); - } - } - - /** - * Return list of comments (if any) during processing of NTP packet. - * - * @return List or null if not yet computed - */ - public List getComments() - { - return _comments; - } - - /** - * Get round-trip network delay. If null then could not compute the delay. - * - * @return Long or null if delay not available. - */ - public Long getDelay() - { - return _delay; - } - - /** - * Get clock offset needed to adjust local clock to match remote clock. If null then could not - * compute the offset. - * - * @return Long or null if offset not available. - */ - public Long getOffset() - { - return _offset; - } - - /** - * Returns NTP message packet. - * - * @return NTP message packet. - */ - public NtpV3Packet getMessage() - { - return _message; - } - - /** - * Returns time at which time message packet was received by local machine. - * - * @return packet return time. - */ - public long getReturnTime() - { - return _returnTime; - } - -} diff --git a/org/apache/commons/net/ntp/TimeStamp.java b/org/apache/commons/net/ntp/TimeStamp.java deleted file mode 100644 index 4cbe26f..0000000 --- a/org/apache/commons/net/ntp/TimeStamp.java +++ /dev/null @@ -1,490 +0,0 @@ -package org.apache.commons.net.ntp; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -import java.lang.ref.SoftReference; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -/*** - * TimeStamp class represents the Network Time Protocol (NTP) timestamp - * as defined in RFC-1305 and SNTP (RFC-2030). It is represented as a - * 64-bit unsigned fixed-point number in seconds relative to 0-hour on 1-January-1900. - * The 32-bit low-order bits are the fractional seconds whose precision is - * about 200 picoseconds. Assumes overflow date when date passes MAX_LONG - * and reverts back to 0 is 2036 and not 1900. Test for most significant - * bit: if MSB=0 then 2036 basis is used otherwise 1900 if MSB=1. - *

- * Methods exist to convert NTP timestamps to and from the equivalent Java date - * representation, which is the number of milliseconds since the standard base - * time known as "the epoch", namely January 1, 1970, 00:00:00 GMT. - *

- * - * @author Jason Mathews, MITRE Corp - * @version $Revision: 658518 $ $Date: 2008-05-21 02:04:30 +0100 (Wed, 21 May 2008) $ - * @see java.util.Date - */ -public class TimeStamp implements java.io.Serializable, Comparable // TODO add comparable type? -{ - - /** - * baseline NTP time if bit-0=0 -> 7-Feb-2036 @ 06:28:16 UTC - */ - protected static final long msb0baseTime = 2085978496000L; - - /** - * baseline NTP time if bit-0=1 -> 1-Jan-1900 @ 01:00:00 UTC - */ - protected static final long msb1baseTime = -2208988800000L; - - /** - * Default NTP date string format. E.g. Fri, Sep 12 2003 21:06:23.860. - * See java.text.SimpleDateFormat for code descriptions. - */ - public final static String NTP_DATE_FORMAT = "EEE, MMM dd yyyy HH:mm:ss.SSS"; - - /* - * Caches for the DateFormatters used by various toString methods. - */ - private static SoftReference simpleFormatter = null; - private static SoftReference utcFormatter = null; - - /** - * NTP timestamp value: 64-bit unsigned fixed-point number as defined in RFC-1305 - * with high-order 32 bits the seconds field and the low-order 32-bits the - * fractional field. - */ - private long ntpTime; - - private static final long serialVersionUID = 8139806907588338737L; - - // initialization of static time bases - /* - static { - TimeZone utcZone = TimeZone.getTimeZone("UTC"); - Calendar calendar = Calendar.getInstance(utcZone); - calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0); - calendar.set(Calendar.MILLISECOND, 0); - msb1baseTime = calendar.getTime().getTime(); - calendar.set(2036, Calendar.FEBRUARY, 7, 6, 28, 16); - calendar.set(Calendar.MILLISECOND, 0); - msb0baseTime = calendar.getTime().getTime(); - } - */ - - /*** - * Constructs a newly allocated NTP timestamp object - * that represents the native 64-bit long argument. - */ - public TimeStamp(long ntpTime) - { - this.ntpTime = ntpTime; - } - - /*** - * Constructs a newly allocated NTP timestamp object - * that represents the value represented by the string - * in hexdecimal form (e.g. "c1a089bd.fc904f6d"). - * - * @throws NumberFormatException - if the string does not contain a parsable timestamp. - */ - public TimeStamp(String s) throws NumberFormatException - { - ntpTime = decodeNtpHexString(s); - } - - /*** - * Constructs a newly allocated NTP timestamp object - * that represents the Java Date argument. - * - * @param d - the Date to be represented by the Timestamp object. - */ - public TimeStamp(Date d) - { - ntpTime = (d == null) ? 0 : toNtpTime(d.getTime()); - } - - /*** - * Returns the value of this Timestamp as a long value. - * - * @return the 64-bit long value represented by this object. - */ - public long ntpValue() - { - return ntpTime; - } - - /*** - * Returns high-order 32-bits representing the seconds of this NTP timestamp. - * - * @return seconds represented by this NTP timestamp. - */ - public long getSeconds() - { - return (ntpTime >>> 32) & 0xffffffffL; - } - - /*** - * Returns low-order 32-bits representing the fractional seconds. - * - * @return fractional seconds represented by this NTP timestamp. - */ - public long getFraction() - { - return ntpTime & 0xffffffffL; - } - - /*** - * Convert NTP timestamp to Java standard time. - * - * @return NTP Timestamp in Java time - */ - public long getTime() - { - return getTime(ntpTime); - } - - /*** - * Convert NTP timestamp to Java Date object. - * - * @return NTP Timestamp in Java Date - */ - public Date getDate() - { - long time = getTime(ntpTime); - return new Date(time); - } - - /*** - * Convert 64-bit NTP timestamp to Java standard time. - * - * Note that java time (milliseconds) by definition has less precision - * then NTP time (picoseconds) so converting NTP timestamp to java time and back - * to NTP timestamp loses precision. For example, Tue, Dec 17 2002 09:07:24.810 EST - * is represented by a single Java-based time value of f22cd1fc8a, but its - * NTP equivalent are all values ranging from c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c. - * - * @param ntpTimeValue - * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT - * represented by this NTP timestamp value. - */ - public static long getTime(long ntpTimeValue) - { - long seconds = (ntpTimeValue >>> 32) & 0xffffffffL; // high-order 32-bits - long fraction = ntpTimeValue & 0xffffffffL; // low-order 32-bits - - // Use round-off on fractional part to preserve going to lower precision - fraction = Math.round(1000D * fraction / 0x100000000L); - - /* - * If the most significant bit (MSB) on the seconds field is set we use - * a different time base. The following text is a quote from RFC-2030 (SNTP v4): - * - * If bit 0 is set, the UTC time is in the range 1968-2036 and UTC time - * is reckoned from 0h 0m 0s UTC on 1 January 1900. If bit 0 is not set, - * the time is in the range 2036-2104 and UTC time is reckoned from - * 6h 28m 16s UTC on 7 February 2036. - */ - long msb = seconds & 0x80000000L; - if (msb == 0) { - // use base: 7-Feb-2036 @ 06:28:16 UTC - return msb0baseTime + (seconds * 1000) + fraction; - } else { - // use base: 1-Jan-1900 @ 01:00:00 UTC - return msb1baseTime + (seconds * 1000) + fraction; - } - } - - /*** - * Helper method to convert Java time to NTP timestamp object. - * Note that Java time (milliseconds) by definition has less precision - * then NTP time (picoseconds) so converting Ntptime to Javatime and back - * to Ntptime loses precision. For example, Tue, Dec 17 2002 09:07:24.810 - * is represented by a single Java-based time value of f22cd1fc8a, but its - * NTP equivalent are all values from c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c. - * @param date the milliseconds since January 1, 1970, 00:00:00 GMT. - * @return NTP timestamp object at the specified date. - */ - public static TimeStamp getNtpTime(long date) - { - return new TimeStamp(toNtpTime(date)); - } - - /*** - * Constructs a NTP timestamp object and initializes it so that - * it represents the time at which it was allocated, measured to the - * nearest millisecond. - * @return NTP timestamp object set to the current time. - * @see java.lang.System#currentTimeMillis() - */ - public static TimeStamp getCurrentTime() - { - return getNtpTime(System.currentTimeMillis()); - } - - /*** - * Convert NTP timestamp hexstring (e.g. "c1a089bd.fc904f6d") to the NTP - * 64-bit unsigned fixed-point number. - * - * @return NTP 64-bit timestamp value. - * @throws NumberFormatException - if the string does not contain a parsable timestamp. - */ - protected static long decodeNtpHexString(String s) - throws NumberFormatException - { - if (s == null) { - throw new NumberFormatException("null"); - } - int ind = s.indexOf('.'); - if (ind == -1) { - if (s.length() == 0) return 0; - return Long.parseLong(s, 16) << 32; // no decimal - } - - return Long.parseLong(s.substring(0, ind), 16) << 32 | - Long.parseLong(s.substring(ind + 1), 16); - } - - /*** - * Parses the string argument as a NTP hexidecimal timestamp representation string - * (e.g. "c1a089bd.fc904f6d"). - * - * @param s - hexstring. - * @return the Timestamp represented by the argument in hexidecimal. - * @throws NumberFormatException - if the string does not contain a parsable timestamp. - */ - public static TimeStamp parseNtpString(String s) - throws NumberFormatException - { - return new TimeStamp(decodeNtpHexString(s)); - } - - /*** - * Converts Java time to 64-bit NTP time representation. - * - * @param t Java time - * @return NTP timestamp representation of Java time value. - */ - protected static long toNtpTime(long t) - { - boolean useBase1 = t < msb0baseTime; // time < Feb-2036 - long baseTime; - if (useBase1) { - baseTime = t - msb1baseTime; // dates <= Feb-2036 - } else { - // if base0 needed for dates >= Feb-2036 - baseTime = t - msb0baseTime; - } - - long seconds = baseTime / 1000; - long fraction = ((baseTime % 1000) * 0x100000000L) / 1000; - - if (useBase1) { - seconds |= 0x80000000L; // set high-order bit if msb1baseTime 1900 used - } - - long time = seconds << 32 | fraction; - return time; - } - - /*** - * Computes a hashcode for this Timestamp. The result is the exclusive - * OR of the two halves of the primitive long value - * represented by this TimeStamp object. That is, the hashcode - * is the value of the expression: - *
-     * (int)(this.ntpValue()^(this.ntpValue() >>> 32))
-     * 
- * - * @return a hash code value for this object. - */ - @Override - public int hashCode() - { - return (int) (ntpTime ^ (ntpTime >>> 32)); - } - - /*** - * Compares this object against the specified object. - * The result is true if and only if the argument is - * not null and is a Long object that - * contains the same long value as this object. - * - * @param obj the object to compare with. - * @return true if the objects are the same; - * false otherwise. - */ - @Override - public boolean equals(Object obj) - { - if (obj instanceof TimeStamp) { - return ntpTime == ((TimeStamp) obj).ntpValue(); - } - return false; - } - - /*** - * Converts this TimeStamp object to a String. - * The NTP timestamp 64-bit long value is represented as hex string with - * seconds separated by fractional seconds by a decimal point; - * e.g. c1a089bd.fc904f6d <=> Tue, Dec 10 2002 10:41:49.986 - * - * @return NTP timestamp 64-bit long value as hex string with seconds - * separated by fractional seconds. - */ - @Override - public String toString() - { - return toString(ntpTime); - } - - /*** - * Left-pad 8-character hex string with 0's - * - * @param buf - StringBuffer which is appended with leading 0's. - * @param l - a long. - */ - private static void appendHexString(StringBuffer buf, long l) - { - String s = Long.toHexString(l); - for (int i = s.length(); i < 8; i++) - buf.append('0'); - buf.append(s); - } - - /*** - * Converts 64-bit NTP timestamp value to a String. - * The NTP timestamp value is represented as hex string with - * seconds separated by fractional seconds by a decimal point; - * e.g. c1a089bd.fc904f6d <=> Tue, Dec 10 2002 10:41:49.986 - * - * @return NTP timestamp 64-bit long value as hex string with seconds - * separated by fractional seconds. - */ - public static String toString(long ntpTime) - { - StringBuffer buf = new StringBuffer(); - // high-order second bits (32..63) as hexstring - appendHexString(buf, (ntpTime >>> 32) & 0xffffffffL); - - // low-order fractional seconds bits (0..31) as hexstring - buf.append('.'); - appendHexString(buf, ntpTime & 0xffffffffL); - - return buf.toString(); - } - - /*** - * Converts this TimeStamp object to a String - * of the form: - *
-     * EEE, MMM dd yyyy HH:mm:ss.SSS
- * See java.text.SimpleDataFormat for code descriptions. - * - * @return a string representation of this date. - */ - public String toDateString() - { - DateFormat formatter = null; - if (simpleFormatter != null) { - formatter = simpleFormatter.get(); - } - if (formatter == null) { - // No cache yet, or cached formatter GC'd - formatter = new SimpleDateFormat(NTP_DATE_FORMAT, Locale.US); - formatter.setTimeZone(TimeZone.getDefault()); - simpleFormatter = new SoftReference(formatter); - } - Date ntpDate = getDate(); - synchronized (formatter) { - return formatter.format(ntpDate); - } - } - - /*** - * Converts this TimeStamp object to a String - * of the form: - *
-     * EEE, MMM dd yyyy HH:mm:ss.SSS UTC
- * See java.text.SimpleDataFormat for code descriptions. - * - * @return a string representation of this date in UTC. - */ - public String toUTCString() - { - DateFormat formatter = null; - if (utcFormatter != null) - formatter = utcFormatter.get(); - if (formatter == null) { - // No cache yet, or cached formatter GC'd - formatter = new SimpleDateFormat(NTP_DATE_FORMAT + " 'UTC'", - Locale.US); - formatter.setTimeZone(TimeZone.getTimeZone("UTC")); - utcFormatter = new SoftReference(formatter); - } - Date ntpDate = getDate(); - synchronized (formatter) { - return formatter.format(ntpDate); - } - } - - /*** - * Compares two Timestamps numerically. - * - * @param anotherTimeStamp - the TimeStamp to be compared. - * @return the value 0 if the argument TimeStamp is equal to - * this TimeStamp; a value less than 0 if this TimeStamp - * is numerically less than the TimeStamp argument; and a - * value greater than 0 if this TimeStamp is - * numerically greater than the TimeStamp argument - * (signed comparison). - */ - public int compareTo(TimeStamp anotherTimeStamp) - { - long thisVal = this.ntpTime; - long anotherVal = anotherTimeStamp.ntpTime; - return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1)); - } - - /*** - * Compares this TimeStamp to another Object. If the Object is a TimeStamp, - * this function behaves like compareTo(TimeStamp). Otherwise, - * it throws a ClassCastException (as TimeStamps are comparable - * only to other TimeStamps). - * - * @param o the Object to be compared. - * @return the value 0 if the argument is a TimeStamp - * numerically equal to this TimeStamp; a value less than - * 0 if the argument is a TimeStamp numerically - * greater than this TimeStamp; and a value greater than - * 0 if the argument is a TimeStamp numerically - * less than this TimeStamp. - * @exception ClassCastException if the argument is not a - * TimeStamp. - * @see java.lang.Comparable - */ - public int compareTo(Object o) - { - return compareTo((TimeStamp) o); - } - -} diff --git a/org/apache/commons/net/pop3/POP3.java b/org/apache/commons/net/pop3/POP3.java deleted file mode 100644 index 80033ab..0000000 --- a/org/apache/commons/net/pop3/POP3.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.Enumeration; -import java.util.Vector; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandListener; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; - -/*** - * The POP3 class is not meant to be used by itself and is provided - * only so that you may easily implement your own POP3 client if - * you so desire. If you have no need to perform your own implementation, - * you should use {@link org.apache.commons.net.pop3.POP3Client}. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @see POP3Client - * @see org.apache.commons.net.MalformedServerReplyException - ***/ - -public class POP3 extends SocketClient -{ - /*** The default POP3 port. Set to 110 according to RFC 1288. ***/ - public static final int DEFAULT_PORT = 110; - /*** - * A constant representing the state where the client is not yet connected - * to a POP3 server. - ***/ - public static final int DISCONNECTED_STATE = -1; - /*** A constant representing the POP3 authorization state. ***/ - public static final int AUTHORIZATION_STATE = 0; - /*** A constant representing the POP3 transaction state. ***/ - public static final int TRANSACTION_STATE = 1; - /*** A constant representing the POP3 update state. ***/ - public static final int UPDATE_STATE = 2; - - static final String _OK = "+OK"; - static final String _ERROR = "-ERR"; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - private static final String __DEFAULT_ENCODING = "ISO-8859-1"; - - private int __popState; - private BufferedWriter __writer; - private StringBuffer __commandBuffer; - - BufferedReader _reader; - int _replyCode; - String _lastReplyLine; - Vector _replyLines; - - /*** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and te firing of ProtocolCommandEvents. - ***/ - protected ProtocolCommandSupport _commandSupport_; - - /*** - * The default POP3Client constructor. Initializes the state - * to DISCONNECTED_STATE. - ***/ - public POP3() - { - setDefaultPort(DEFAULT_PORT); - __commandBuffer = new StringBuffer(); - __popState = DISCONNECTED_STATE; - _reader = null; - __writer = null; - _replyLines = new Vector(); - _commandSupport_ = new ProtocolCommandSupport(this); - } - - private void __getReply() throws IOException - { - String line; - - _replyLines.setSize(0); - line = _reader.readLine(); - - if (line == null) - throw new EOFException("Connection closed without indication."); - - if (line.startsWith(_OK)) - _replyCode = POP3Reply.OK; - else if (line.startsWith(_ERROR)) - _replyCode = POP3Reply.ERROR; - else - throw new - MalformedServerReplyException( - "Received invalid POP3 protocol response from server."); - - _replyLines.addElement(line); - _lastReplyLine = line; - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); - } - - - /*** - * Performs connection initialization and sets state to - * AUTHORIZATION_STATE . - ***/ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - _reader = - new BufferedReader(new InputStreamReader(_input_, - __DEFAULT_ENCODING)); - __writer = - new BufferedWriter(new OutputStreamWriter(_output_, - __DEFAULT_ENCODING)); - __getReply(); - setState(AUTHORIZATION_STATE); - } - - - /*** - * Adds a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to add. - ***/ - public void addProtocolCommandListener(ProtocolCommandListener listener) - { - _commandSupport_.addProtocolCommandListener(listener); - } - - /*** - * Removes a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to remove. - ***/ - public void removeProtocolCommandistener(ProtocolCommandListener listener) - { - _commandSupport_.removeProtocolCommandListener(listener); - } - - - /*** - * Sets POP3 client state. This must be one of the - * _STATE constants. - *

- * @param state The new state. - ***/ - public void setState(int state) - { - __popState = state; - } - - - /*** - * Returns the current POP3 client state. - *

- * @return The current POP3 client state. - ***/ - public int getState() - { - return __popState; - } - - - /*** - * Retrieves the additional lines of a multi-line server reply. - ***/ - public void getAdditionalReply() throws IOException - { - String line; - - line = _reader.readLine(); - while (line != null) - { - _replyLines.addElement(line); - if (line.equals(".")) - break; - line = _reader.readLine(); - } - } - - - /*** - * Disconnects the client from the server, and sets the state to - * DISCONNECTED_STATE . The reply text information - * from the last issued command is voided to allow garbage collection - * of the memory used to store that information. - *

- * @exception IOException If there is an error in disconnecting. - ***/ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - _reader = null; - __writer = null; - _lastReplyLine = null; - _replyLines.setSize(0); - setState(DISCONNECTED_STATE); - } - - - /*** - * Sends a command an arguments to the server and returns the reply code. - *

- * @param command The POP3 command to send. - * @param args The command arguments. - * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). - ***/ - public int sendCommand(String command, String args) throws IOException - { - String message; - - __commandBuffer.setLength(0); - __commandBuffer.append(command); - - if (args != null) - { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - - __writer.write(message = __commandBuffer.toString()); - __writer.flush(); - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireCommandSent(command, message); - - __getReply(); - return _replyCode; - } - - /*** - * Sends a command with no arguments to the server and returns the - * reply code. - *

- * @param command The POP3 command to send. - * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). - ***/ - public int sendCommand(String command) throws IOException - { - return sendCommand(command, null); - } - - /*** - * Sends a command an arguments to the server and returns the reply code. - *

- * @param command The POP3 command to send - * (one of the POP3Command constants). - * @param args The command arguments. - * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). - ***/ - public int sendCommand(int command, String args) throws IOException - { - return sendCommand(POP3Command._commands[command], args); - } - - /*** - * Sends a command with no arguments to the server and returns the - * reply code. - *

- * @param command The POP3 command to send - * (one of the POP3Command constants). - * @return The server reply code (either POP3Reply.OK or POP3Reply.ERROR). - ***/ - public int sendCommand(int command) throws IOException - { - return sendCommand(POP3Command._commands[command], null); - } - - - /*** - * Returns an array of lines received as a reply to the last command - * sent to the server. The lines have end of lines truncated. If - * the reply is a single line, but its format ndicates it should be - * a multiline reply, then you must call - * {@link #getAdditionalReply getAdditionalReply() } to - * fetch the rest of the reply, and then call getReplyStrings - * again. You only have to worry about this if you are implementing - * your own client using the {@link #sendCommand sendCommand } methods. - *

- * @return The last server response. - ***/ - public String[] getReplyStrings() - { - String[] lines; - lines = new String[_replyLines.size()]; - _replyLines.copyInto(lines); - return lines; - } - - /*** - * Returns the reply to the last command sent to the server. - * The value is a single string containing all the reply lines including - * newlines. If the reply is a single line, but its format ndicates it - * should be a multiline reply, then you must call - * {@link #getAdditionalReply getAdditionalReply() } to - * fetch the rest of the reply, and then call getReplyString - * again. You only have to worry about this if you are implementing - * your own client using the {@link #sendCommand sendCommand } methods. - *

- * @return The last server response. - ***/ - public String getReplyString() - { - Enumeration en; - StringBuffer buffer = new StringBuffer(256); - - en = _replyLines.elements(); - while (en.hasMoreElements()) - { - buffer.append(en.nextElement()); - buffer.append(SocketClient.NETASCII_EOL); - } - - return buffer.toString(); - } - -} - diff --git a/org/apache/commons/net/pop3/POP3Client.java b/org/apache/commons/net/pop3/POP3Client.java deleted file mode 100644 index c5e9a96..0000000 --- a/org/apache/commons/net/pop3/POP3Client.java +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -import java.io.IOException; -import java.io.Reader; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Enumeration; -import java.util.StringTokenizer; - -import org.apache.commons.net.io.DotTerminatedMessageReader; - -/*** - * The POP3Client class implements the client side of the Internet POP3 - * Protocol defined in RFC 1939. All commands are supported, including - * the APOP command which requires MD5 encryption. See RFC 1939 for - * more details on the POP3 protocol. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @see POP3MessageInfo - * @see org.apache.commons.net.io.DotTerminatedMessageReader - * @see org.apache.commons.net.MalformedServerReplyException - ***/ - -public class POP3Client extends POP3 -{ - - private static POP3MessageInfo __parseStatus(String line) - { - int num, size; - StringTokenizer tokenizer; - - tokenizer = new StringTokenizer(line); - - if (!tokenizer.hasMoreElements()) - return null; - - num = size = 0; - - try - { - num = Integer.parseInt(tokenizer.nextToken()); - - if (!tokenizer.hasMoreElements()) - return null; - - size = Integer.parseInt(tokenizer.nextToken()); - } - catch (NumberFormatException e) - { - return null; - } - - return new POP3MessageInfo(num, size); - } - - private static POP3MessageInfo __parseUID(String line) - { - int num; - StringTokenizer tokenizer; - - tokenizer = new StringTokenizer(line); - - if (!tokenizer.hasMoreElements()) - return null; - - num = 0; - - try - { - num = Integer.parseInt(tokenizer.nextToken()); - - if (!tokenizer.hasMoreElements()) - return null; - - line = tokenizer.nextToken(); - } - catch (NumberFormatException e) - { - return null; - } - - return new POP3MessageInfo(num, line); - } - - /*** - * Login to the POP3 server with the given username and password. You - * must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before attempting to login. A login attempt is only valid if - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#AUTHORIZATION_STATE AUTHORIZATION_STATE } - * . After logging in, the client enters the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - *

- * @param username The account name being logged in to. - * @param password The plain text password of the account. - * @return True if the login attempt was successful, false if not. - * @exception IOException If a network I/O error occurs in the process of - * logging in. - ***/ - public boolean login(String username, String password) throws IOException - { - if (getState() != AUTHORIZATION_STATE) - return false; - - if (sendCommand(POP3Command.USER, username) != POP3Reply.OK) - return false; - - if (sendCommand(POP3Command.PASS, password) != POP3Reply.OK) - return false; - - setState(TRANSACTION_STATE); - - return true; - } - - - /*** - * Login to the POP3 server with the given username and authentication - * information. Use this method when connecting to a server requiring - * authentication using the APOP command. Because the timestamp - * produced in the greeting banner varies from server to server, it is - * not possible to consistently extract the information. Therefore, - * after connecting to the server, you must call - * {@link org.apache.commons.net.pop3.POP3#getReplyString getReplyString } - * and parse out the timestamp information yourself. - *

- * You must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before attempting to login. A login attempt is only valid if - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#AUTHORIZATION_STATE AUTHORIZATION_STATE } - * . After logging in, the client enters the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . After connecting, you must parse out the - * server specific information to use as a timestamp, and pass that - * information to this method. The secret is a shared secret known - * to you and the server. See RFC 1939 for more details regarding - * the APOP command. - *

- * @param username The account name being logged in to. - * @param timestamp The timestamp string to combine with the secret. - * @param secret The shared secret which produces the MD5 digest when - * combined with the timestamp. - * @return True if the login attempt was successful, false if not. - * @exception IOException If a network I/O error occurs in the process of - * logging in. - * @exception NoSuchAlgorithmException If the MD5 encryption algorithm - * cannot be instantiated by the Java runtime system. - ***/ - public boolean login(String username, String timestamp, String secret) - throws IOException, NoSuchAlgorithmException - { - int i; - byte[] digest; - StringBuffer buffer, digestBuffer; - MessageDigest md5; - - if (getState() != AUTHORIZATION_STATE) - return false; - - md5 = MessageDigest.getInstance("MD5"); - timestamp += secret; - digest = md5.digest(timestamp.getBytes()); - digestBuffer = new StringBuffer(128); - - for (i = 0; i < digest.length; i++) - digestBuffer.append(Integer.toHexString(digest[i] & 0xff)); - - buffer = new StringBuffer(256); - buffer.append(username); - buffer.append(' '); - buffer.append(digestBuffer.toString()); - - if (sendCommand(POP3Command.APOP, buffer.toString()) != POP3Reply.OK) - return false; - - setState(TRANSACTION_STATE); - - return true; - } - - - /*** - * Logout of the POP3 server. To fully disconnect from the server - * you must call - * {@link org.apache.commons.net.pop3.POP3#disconnect disconnect }. - * A logout attempt is valid in any state. If - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * , it enters the - * {@link org.apache.commons.net.pop3.POP3#UPDATE_STATE UPDATE_STATE } - * on a successful logout. - *

- * @return True if the logout attempt was successful, false if not. - * @exception IOException If a network I/O error occurs in the process - * of logging out. - ***/ - public boolean logout() throws IOException - { - if (getState() == TRANSACTION_STATE) - setState(UPDATE_STATE); - sendCommand(POP3Command.QUIT); - return (_replyCode == POP3Reply.OK); - } - - - /*** - * Send a NOOP command to the POP3 server. This is useful for keeping - * a connection alive since most POP3 servers will timeout after 10 - * minutes of inactivity. A noop attempt will only succeed if - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - *

- * @return True if the noop attempt was successful, false if not. - * @exception IOException If a network I/O error occurs in the process of - * sending the NOOP command. - ***/ - public boolean noop() throws IOException - { - if (getState() == TRANSACTION_STATE) - return (sendCommand(POP3Command.NOOP) == POP3Reply.OK); - return false; - } - - - /*** - * Delete a message from the POP3 server. The message is only marked - * for deletion by the server. If you decide to unmark the message, you - * must issuse a {@link #reset reset } command. Messages marked - * for deletion are only deleted by the server on - * {@link #logout logout }. - * A delete attempt can only succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - *

- * @param messageId The message number to delete. - * @return True if the deletion attempt was successful, false if not. - * @exception IOException If a network I/O error occurs in the process of - * sending the delete command. - ***/ - public boolean deleteMessage(int messageId) throws IOException - { - if (getState() == TRANSACTION_STATE) - return (sendCommand(POP3Command.DELE, Integer.toString(messageId)) - == POP3Reply.OK); - return false; - } - - - /*** - * Reset the POP3 session. This is useful for undoing any message - * deletions that may have been performed. A reset attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - *

- * @return True if the reset attempt was successful, false if not. - * @exception IOException If a network I/O error occurs in the process of - * sending the reset command. - ***/ - public boolean reset() throws IOException - { - if (getState() == TRANSACTION_STATE) - return (sendCommand(POP3Command.RSET) == POP3Reply.OK); - return false; - } - - /*** - * Get the mailbox status. A status attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a POP3MessageInfo instance - * containing the number of messages in the mailbox and the total - * size of the messages in bytes. Returns null if the status the - * attempt fails. - *

- * @return A POP3MessageInfo instance containing the number of - * messages in the mailbox and the total size of the messages - * in bytes. Returns null if the status the attempt fails. - * @exception IOException If a network I/O error occurs in the process of - * sending the status command. - ***/ - public POP3MessageInfo status() throws IOException - { - if (getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.STAT) != POP3Reply.OK) - return null; - return __parseStatus(_lastReplyLine.substring(3)); - } - - - /*** - * List an individual message. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a POP3MessageInfo instance - * containing the number of the listed message and the - * size of the message in bytes. Returns null if the list - * attempt fails (e.g., if the specified message number does - * not exist). - *

- * @param messageId The number of the message list. - * @return A POP3MessageInfo instance containing the number of the - * listed message and the size of the message in bytes. Returns - * null if the list attempt fails. - * @exception IOException If a network I/O error occurs in the process of - * sending the list command. - ***/ - public POP3MessageInfo listMessage(int messageId) throws IOException - { - if (getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.LIST, Integer.toString(messageId)) - != POP3Reply.OK) - return null; - return __parseStatus(_lastReplyLine.substring(3)); - } - - - /*** - * List all messages. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns an array of POP3MessageInfo instances, - * each containing the number of a message and its size in bytes. - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - *

- * @return An array of POP3MessageInfo instances representing all messages - * in the order they appear in the mailbox, - * each containing the number of a message and its size in bytes. - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - * @exception IOException If a network I/O error occurs in the process of - * sending the list command. - ***/ - public POP3MessageInfo[] listMessages() throws IOException - { - POP3MessageInfo[] messages; - Enumeration en; - int line; - - if (getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.LIST) != POP3Reply.OK) - return null; - getAdditionalReply(); - - // This could be a zero length array if no messages present - messages = new POP3MessageInfo[_replyLines.size() - 2]; - en = _replyLines.elements(); - - // Skip first line - en.nextElement(); - - // Fetch lines. - for (line = 0; line < messages.length; line++) - messages[line] = __parseStatus(en.nextElement()); - - return messages; - } - - /*** - * List the unique identifier for a message. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a POP3MessageInfo instance - * containing the number of the listed message and the - * unique identifier for that message. Returns null if the list - * attempt fails (e.g., if the specified message number does - * not exist). - *

- * @param messageId The number of the message list. - * @return A POP3MessageInfo instance containing the number of the - * listed message and the unique identifier for that message. - * Returns null if the list attempt fails. - * @exception IOException If a network I/O error occurs in the process of - * sending the list unique identifier command. - ***/ - public POP3MessageInfo listUniqueIdentifier(int messageId) - throws IOException - { - if (getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.UIDL, Integer.toString(messageId)) - != POP3Reply.OK) - return null; - return __parseUID(_lastReplyLine.substring(3)); - } - - - /*** - * List the unique identifiers for all messages. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns an array of POP3MessageInfo instances, - * each containing the number of a message and its unique identifier. - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - *

- * @return An array of POP3MessageInfo instances representing all messages - * in the order they appear in the mailbox, - * each containing the number of a message and its unique identifier - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - * @exception IOException If a network I/O error occurs in the process of - * sending the list unique identifier command. - ***/ - public POP3MessageInfo[] listUniqueIdentifiers() throws IOException - { - POP3MessageInfo[] messages; - Enumeration en; - int line; - - if (getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.UIDL) != POP3Reply.OK) - return null; - getAdditionalReply(); - - // This could be a zero length array if no messages present - messages = new POP3MessageInfo[_replyLines.size() - 2]; - en = _replyLines.elements(); - - // Skip first line - en.nextElement(); - - // Fetch lines. - for (line = 0; line < messages.length; line++) - messages[line] = __parseUID(en.nextElement()); - - return messages; - } - - - /*** - * Retrieve a message from the POP3 server. A retrieve message attempt - * can only succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a DotTerminatedMessageReader instance - * from which the entire message can be read. - * Returns null if the retrieval attempt fails (e.g., if the specified - * message number does not exist). - *

- * You must not issue any commands to the POP3 server (i.e., call any - * other methods) until you finish reading the message from the - * returned Reader instance. - * The POP3 protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the POP3 connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param messageId The number of the message to fetch. - * @return A DotTerminatedMessageReader instance - * from which the entire message can be read. - * Returns null if the retrieval attempt fails (e.g., if the specified - * message number does not exist). - * @exception IOException If a network I/O error occurs in the process of - * sending the retrieve message command. - ***/ - public Reader retrieveMessage(int messageId) throws IOException - { - if (getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.RETR, Integer.toString(messageId)) - != POP3Reply.OK) - return null; - - return new DotTerminatedMessageReader(_reader); - } - - - /*** - * Retrieve only the specified top number of lines of a message from the - * POP3 server. A retrieve top lines attempt - * can only succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a DotTerminatedMessageReader instance - * from which the specified top number of lines of the message can be - * read. - * Returns null if the retrieval attempt fails (e.g., if the specified - * message number does not exist). - *

- * You must not issue any commands to the POP3 server (i.e., call any - * other methods) until you finish reading the message from the returned - * Reader instance. - * The POP3 protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned Reader actually reads - * directly from the POP3 connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - *

- * @param messageId The number of the message to fetch. - * @param numLines The top number of lines to fetch. This must be >= 0. - * @return A DotTerminatedMessageReader instance - * from which the specified top number of lines of the message can be - * read. - * Returns null if the retrieval attempt fails (e.g., if the specified - * message number does not exist). - * @exception IOException If a network I/O error occurs in the process of - * sending the top command. - ***/ - public Reader retrieveMessageTop(int messageId, int numLines) - throws IOException - { - if (numLines < 0 || getState() != TRANSACTION_STATE) - return null; - if (sendCommand(POP3Command.TOP, Integer.toString(messageId) + " " + - Integer.toString(numLines)) != POP3Reply.OK) - return null; - - return new DotTerminatedMessageReader(_reader); - } - - -} - diff --git a/org/apache/commons/net/pop3/POP3Command.java b/org/apache/commons/net/pop3/POP3Command.java deleted file mode 100644 index 0f583bc..0000000 --- a/org/apache/commons/net/pop3/POP3Command.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -/*** - * POP3Command stores POP3 command code constants. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class POP3Command -{ - /*** Send user name. ***/ - public static final int USER = 0; - /*** Send password. ***/ - public static final int PASS = 1; - /*** Quit session. ***/ - public static final int QUIT = 2; - /*** Get status. ***/ - public static final int STAT = 3; - /*** List message(s). ***/ - public static final int LIST = 4; - /*** Retrieve message(s). ***/ - public static final int RETR = 5; - /*** Delete message(s). ***/ - public static final int DELE = 6; - /*** No operation. Used as a session keepalive. ***/ - public static final int NOOP = 7; - /*** Reset session. ***/ - public static final int RSET = 8; - /*** Authorization. ***/ - public static final int APOP = 9; - /*** Retrieve top number lines from message. ***/ - public static final int TOP = 10; - /*** List unique message identifier(s). ***/ - public static final int UIDL = 11; - - static final String[] _commands = { - "USER", "PASS", "QUIT", "STAT", "LIST", "RETR", "DELE", "NOOP", "RSET", - "APOP", "TOP", "UIDL" - }; - - // Cannot be instantiated. - private POP3Command() - {} - - /*** - * Get the POP3 protocol string command corresponding to a command code. - *

- * @return The POP3 protocol string command corresponding to a command code. - ***/ - public static final String getCommand(int command) - { - return _commands[command]; - } -} diff --git a/org/apache/commons/net/pop3/POP3MessageInfo.java b/org/apache/commons/net/pop3/POP3MessageInfo.java deleted file mode 100644 index 070fd69..0000000 --- a/org/apache/commons/net/pop3/POP3MessageInfo.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -/*** - * POP3MessageInfo is used to return information about messages stored on - * a POP3 server. Its fields are used to mean slightly different things - * depending on the information being returned. - *

- * In response to a status command, number - * contains the number of messages in the mailbox, size - * contains the size of the mailbox in bytes, and identifier - * is null. - *

- * In response to a message listings, number - * contains the message number, size contains the - * size of the message in bytes, and identifier is null. - *

- * In response to unique identifier listings, number contains - * the message number, size is undefined, and - * identifier contains the message's unique identifier. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class POP3MessageInfo -{ - public int number; - public int size; - public String identifier; - - /*** - * Creates a POP3MessageInfo instance with number and - * size set to 0, and identifier set to - * null. - ***/ - public POP3MessageInfo() - { - number = size = 0; - identifier = null; - } - - /*** - * Creates a POP3MessageInfo instance with number set - * to num , size set to octets , - * and identifier set to null. - ***/ - public POP3MessageInfo(int num, int octets) - { - number = num; - size = octets; - identifier = null; - } - - /*** - * Creates a POP3MessageInfo instance with number set - * to num , size undefined, - * and identifier set to uid. - ***/ - public POP3MessageInfo(int num, String uid) - { - number = num; - size = -1; - identifier = uid; - } -} diff --git a/org/apache/commons/net/pop3/POP3Reply.java b/org/apache/commons/net/pop3/POP3Reply.java deleted file mode 100644 index 08e4246..0000000 --- a/org/apache/commons/net/pop3/POP3Reply.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -/*** - * POP3Reply stores POP3 reply code constants. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class POP3Reply -{ - /*** The reply code indicating success of an operation. ***/ - public static final int OK = 0; - - /*** The reply code indicating failure of an operation. ***/ - public static final int ERROR = 1; - - // Cannot be instantiated. - private POP3Reply() - {} -} diff --git a/org/apache/commons/net/smtp/RelayPath.java b/org/apache/commons/net/smtp/RelayPath.java deleted file mode 100644 index 62d1098..0000000 --- a/org/apache/commons/net/smtp/RelayPath.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.util.Enumeration; -import java.util.Vector; - -/*** - * A class used to represent forward and reverse relay paths. The - * SMTP MAIL command requires a reverse relay path while the SMTP RCPT - * command requires a forward relay path. See RFC 821 for more details. - * In general, you will not have to deal with relay paths. - *

- *

- * @author Daniel F. Savarese - * @see SMTPClient - ***/ - -public final class RelayPath -{ - Vector _path; - String _emailAddress; - - /*** - * Create a relay path with the specified email address as the ultimate - * destination. - *

- * @param emailAddress The destination email address. - ***/ - public RelayPath(String emailAddress) - { - _path = new Vector(); - _emailAddress = emailAddress; - } - - /*** - * Add a mail relay host to the relay path. Hosts are added left to - * right. For example, the following will create the path - * < @bar.com,@foo.com:foobar@foo.com > - *

-     * path = new RelayPath("foobar@foo.com");
-     * path.addRelay("bar.com");
-     * path.addRelay("foo.com");
-     * 
- *

- * @param hostname The host to add to the relay path. - ***/ - public void addRelay(String hostname) - { - _path.addElement(hostname); - } - - /*** - * Return the properly formatted string representation of the relay path. - *

- * @return The properly formatted string representation of the relay path. - ***/ - @Override - public String toString() - { - StringBuffer buffer = new StringBuffer(); - Enumeration hosts; - - buffer.append('<'); - - hosts = _path.elements(); - - if (hosts.hasMoreElements()) - { - buffer.append('@'); - buffer.append(hosts.nextElement()); - - while (hosts.hasMoreElements()) - { - buffer.append(",@"); - buffer.append(hosts.nextElement()); - } - buffer.append(':'); - } - - buffer.append(_emailAddress); - buffer.append('>'); - - return buffer.toString(); - } - -} diff --git a/org/apache/commons/net/smtp/SMTP.java b/org/apache/commons/net/smtp/SMTP.java deleted file mode 100644 index 0a628b1..0000000 --- a/org/apache/commons/net/smtp/SMTP.java +++ /dev/null @@ -1,777 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.ArrayList; -import java.util.Arrays; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandListener; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; - -/*** - * SMTP provides the basic the functionality necessary to implement your - * own SMTP client. To derive the full benefits of the SMTP class requires - * some knowledge of the FTP protocol defined in RFC 821. However, there - * is no reason why you should have to use the SMTP class. The - * {@link org.apache.commons.net.smtp.SMTPClient} class, - * derived from SMTP, - * implements all the functionality required of an SMTP client. The - * SMTP class is made public to provide access to various SMTP constants - * and to make it easier for adventurous programmers (or those with - * special needs) to interact with the SMTP protocol and implement their - * own clients. A set of methods with names corresponding to the SMTP - * command names are provided to facilitate this interaction. - *

- * You should keep in mind that the SMTP server may choose to prematurely - * close a connection for various reasons. The SMTP class will detect a - * premature SMTP server connection closing when it receives a - * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the SMTP class method encountering that reply will throw - * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * . - * SMTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * , you must disconnect the connection with - * {@link org.apache.commons.net.SocketClient#disconnect disconnect() } - * to properly clean up the system resources used by SMTP. Before - * disconnecting, you may check the - * last reply code and text with - * {@link #getReplyCode getReplyCode }, - * {@link #getReplyString getReplyString }, - * and {@link #getReplyStrings getReplyStrings}. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @see SMTPClient - * @see SMTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - ***/ - -public class SMTP extends SocketClient -{ - /*** The default SMTP port (25). ***/ - public static final int DEFAULT_PORT = 25; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - private static final String __DEFAULT_ENCODING = "ISO-8859-1"; - - /** The encoding to use (user-settable) */ - private String encoding = __DEFAULT_ENCODING; - - private StringBuffer __commandBuffer; - - BufferedReader _reader; - BufferedWriter _writer; - int _replyCode; - ArrayList _replyLines; - boolean _newReplyString; - String _replyString; - - /*** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and te firing of ProtocolCommandEvents. - ***/ - protected ProtocolCommandSupport _commandSupport_; - - /*** - * The default SMTP constructor. Sets the default port to - * DEFAULT_PORT and initializes internal data structures - * for saving SMTP reply information. - ***/ - public SMTP() - { - setDefaultPort(DEFAULT_PORT); - __commandBuffer = new StringBuffer(); - _replyLines = new ArrayList(); - _newReplyString = false; - _replyString = null; - _commandSupport_ = new ProtocolCommandSupport(this); - } - - /** - * Overloaded constructor where the user may specify a default encoding. - * @param encoding - * @since 2.0 - */ - public SMTP(String encoding) { - this(); - this.encoding = encoding; - } - - private int __sendCommand(String command, String args, boolean includeSpace) - throws IOException - { - String message; - - __commandBuffer.setLength(0); - __commandBuffer.append(command); - - if (args != null) - { - if (includeSpace) - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - - __commandBuffer.append(SocketClient.NETASCII_EOL); - - _writer.write(message = __commandBuffer.toString()); - _writer.flush(); - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireCommandSent(command, message); - - __getReply(); - return _replyCode; - } - - private int __sendCommand(int command, String args, boolean includeSpace) - throws IOException - { - return __sendCommand(SMTPCommand._commands[command], args, includeSpace); - } - - private void __getReply() throws IOException - { - int length; - - _newReplyString = true; - _replyLines.clear(); - - String line = _reader.readLine(); - - if (line == null) - throw new SMTPConnectionClosedException( - "Connection closed without indication."); - - // In case we run into an anomaly we don't want fatal index exceptions - // to be thrown. - length = line.length(); - if (length < 3) - throw new MalformedServerReplyException( - "Truncated server reply: " + line); - - try - { - String code = line.substring(0, 3); - _replyCode = Integer.parseInt(code); - } - catch (NumberFormatException e) - { - throw new MalformedServerReplyException( - "Could not parse response code.\nServer Reply: " + line); - } - - _replyLines.add(line); - - // Get extra lines if message continues. - if (length > 3 && line.charAt(3) == '-') - { - do - { - line = _reader.readLine(); - - if (line == null) - throw new SMTPConnectionClosedException( - "Connection closed without indication."); - - _replyLines.add(line); - - // The length() check handles problems that could arise from readLine() - // returning too soon after encountering a naked CR or some other - // anomaly. - } - while (!(line.length() >= 4 && line.charAt(3) != '-' && - Character.isDigit(line.charAt(0)))); - // This is too strong a condition because a non-conforming server - // could screw things up like ftp.funet.fi does for FTP - // line.startsWith(code))); - } - - if (_commandSupport_.getListenerCount() > 0) - _commandSupport_.fireReplyReceived(_replyCode, getReplyString()); - - if (_replyCode == SMTPReply.SERVICE_NOT_AVAILABLE) - throw new SMTPConnectionClosedException( - "SMTP response 421 received. Server closed connection."); - } - - /*** Initiates control connections and gets initial reply. ***/ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - _reader = - new BufferedReader(new InputStreamReader(_input_, - encoding)); - _writer = - new BufferedWriter(new OutputStreamWriter(_output_, - encoding)); - __getReply(); - - } - - - /*** - * Adds a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to add. - ***/ - public void addProtocolCommandListener(ProtocolCommandListener listener) - { - _commandSupport_.addProtocolCommandListener(listener); - } - - /*** - * Removes a ProtocolCommandListener. Delegates this task to - * {@link #_commandSupport_ _commandSupport_ }. - *

- * @param listener The ProtocolCommandListener to remove. - ***/ - public void removeProtocolCommandistener(ProtocolCommandListener listener) - { - _commandSupport_.removeProtocolCommandListener(listener); - } - - - /*** - * Closes the connection to the SMTP server and sets to null - * some internal data so that the memory may be reclaimed by the - * garbage collector. The reply text and code information from the - * last command is voided so that the memory it used may be reclaimed. - *

- * @exception IOException If an error occurs while disconnecting. - ***/ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - _reader = null; - _writer = null; - _replyString = null; - _replyLines.clear(); - _newReplyString = false; - } - - - /*** - * Sends an SMTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The text representation of the SMTP command to send. - * @param args The arguments to the SMTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command, String args) throws IOException - { - return __sendCommand(command, args, true); - } - - - /*** - * Sends an SMTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The SMTPCommand constant corresponding to the SMTP command - * to send. - * @param args The arguments to the SMTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command, String args) throws IOException - { - return sendCommand(SMTPCommand._commands[command], args); - } - - - /*** - * Sends an SMTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The text representation of the SMTP command to send. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command) throws IOException - { - return sendCommand(command, null); - } - - - /*** - * Sends an SMTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The SMTPCommand constant corresponding to the SMTP command - * to send. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command) throws IOException - { - return sendCommand(command, null); - } - - - /*** - * Returns the integer value of the reply code of the last SMTP reply. - * You will usually only use this method after you connect to the - * SMTP server to check that the connection was successful since - * connect is of type void. - *

- * @return The integer value of the reply code of the last SMTP reply. - ***/ - public int getReplyCode() - { - return _replyCode; - } - - /*** - * Fetches a reply from the SMTP server and returns the integer reply - * code. After calling this method, the actual reply text can be accessed - * from either calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. Only use this - * method if you are implementing your own SMTP client or if you need to - * fetch a secondary response from the SMTP server. - *

- * @return The integer value of the reply code of the fetched SMTP reply. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while receiving the - * server reply. - ***/ - public int getReply() throws IOException - { - __getReply(); - return _replyCode; - } - - - /*** - * Returns the lines of text from the last SMTP server response as an array - * of strings, one entry per line. The end of line markers of each are - * stripped from each line. - *

- * @return The lines of text from the last SMTP response as an array. - ***/ - public String[] getReplyStrings() - { - String[] lines; - lines = new String[_replyLines.size()]; - _replyLines.addAll(Arrays.asList(lines)); - return lines; - } - - /*** - * Returns the entire text of the last SMTP server response exactly - * as it was received, including all end of line markers in NETASCII - * format. - *

- * @return The entire text from the last SMTP response as a String. - ***/ - public String getReplyString() - { - StringBuilder buffer; - - if (!_newReplyString) - return _replyString; - - buffer = new StringBuilder(); - - for (String line : _replyLines) - { - buffer.append(line); - buffer.append(SocketClient.NETASCII_EOL); - } - - _newReplyString = false; - - return (_replyString = buffer.toString()); - } - - - /*** - * A convenience method to send the SMTP HELO command to the server, - * receive the reply, and return the reply code. - *

- * @param hostname The hostname of the sender. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int helo(String hostname) throws IOException - { - return sendCommand(SMTPCommand.HELO, hostname); - } - - - /*** - * A convenience method to send the SMTP MAIL command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int mail(String reversePath) throws IOException - { - return __sendCommand(SMTPCommand.MAIL, reversePath, false); - } - - - /*** - * A convenience method to send the SMTP RCPT command to the server, - * receive the reply, and return the reply code. - *

- * @param forwardPath The forward path. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rcpt(String forwardPath) throws IOException - { - return __sendCommand(SMTPCommand.RCPT, forwardPath, false); - } - - - /*** - * A convenience method to send the SMTP DATA command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int data() throws IOException - { - return sendCommand(SMTPCommand.DATA); - } - - - /*** - * A convenience method to send the SMTP SEND command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int send(String reversePath) throws IOException - { - return sendCommand(SMTPCommand.SEND, reversePath); - } - - - /*** - * A convenience method to send the SMTP SOML command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int soml(String reversePath) throws IOException - { - return sendCommand(SMTPCommand.SOML, reversePath); - } - - - /*** - * A convenience method to send the SMTP SAML command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int saml(String reversePath) throws IOException - { - return sendCommand(SMTPCommand.SAML, reversePath); - } - - - /*** - * A convenience method to send the SMTP RSET command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rset() throws IOException - { - return sendCommand(SMTPCommand.RSET); - } - - - /*** - * A convenience method to send the SMTP VRFY command to the server, - * receive the reply, and return the reply code. - *

- * @param user The user address to verify. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int vrfy(String user) throws IOException - { - return sendCommand(SMTPCommand.VRFY, user); - } - - - /*** - * A convenience method to send the SMTP VRFY command to the server, - * receive the reply, and return the reply code. - *

- * @param name The name to expand. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int expn(String name) throws IOException - { - return sendCommand(SMTPCommand.EXPN, name); - } - - /*** - * A convenience method to send the SMTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help() throws IOException - { - return sendCommand(SMTPCommand.HELP); - } - - /*** - * A convenience method to send the SMTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @param command The command name on which to request help. - * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help(String command) throws IOException - { - return sendCommand(SMTPCommand.HELP, command); - } - - /*** - * A convenience method to send the SMTP NOOP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int noop() throws IOException - { - return sendCommand(SMTPCommand.NOOP); - } - - - /*** - * A convenience method to send the SMTP TURN command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int turn() throws IOException - { - return sendCommand(SMTPCommand.TURN); - } - - - /*** - * A convenience method to send the SMTP QUIT command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int quit() throws IOException - { - return sendCommand(SMTPCommand.QUIT); - } - -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/smtp/SMTPClient.java b/org/apache/commons/net/smtp/SMTPClient.java deleted file mode 100644 index 8b9ed45..0000000 --- a/org/apache/commons/net/smtp/SMTPClient.java +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.IOException; -import java.io.Writer; -import java.net.InetAddress; - -import org.apache.commons.net.io.DotTerminatedMessageWriter; - -/*** - * SMTPClient encapsulates all the functionality necessary to send files - * through an SMTP server. This class takes care of all - * low level details of interacting with an SMTP server and provides - * a convenient higher level interface. As with all classes derived - * from {@link org.apache.commons.net.SocketClient}, - * you must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before doing anything, and finally - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after you're completely finished interacting with the server. - * Then you need to check the SMTP reply code to see if the connection - * was successful. For example: - *

- *    try {
- *      int reply;
- *      client.connect("mail.foobar.com");
- *      System.out.print(client.getReplyString());
- *
- *      // After connection attempt, you should check the reply code to verify
- *      // success.
- *      reply = client.getReplyCode();
- *
- *      if(!SMTPReply.isPositiveCompletion(reply)) {
- *        client.disconnect();
- *        System.err.println("SMTP server refused connection.");
- *        System.exit(1);
- *      }
- *
- *      // Do useful stuff here.
- *      ...
- *    } catch(IOException e) {
- *      if(client.isConnected()) {
- *        try {
- *          client.disconnect();
- *        } catch(IOException f) {
- *          // do nothing
- *        }
- *      }
- *      System.err.println("Could not connect to server.");
- *      e.printStackTrace();
- *      System.exit(1);
- *    }
- * 
- *

- * Immediately after connecting is the only real time you need to check the - * reply code (because connect is of type void). The convention for all the - * SMTP command methods in SMTPClient is such that they either return a - * boolean value or some other value. - * The boolean methods return true on a successful completion reply from - * the SMTP server and false on a reply resulting in an error condition or - * failure. The methods returning a value other than boolean return a value - * containing the higher level data produced by the SMTP command, or null if a - * reply resulted in an error condition or failure. If you want to access - * the exact SMTP reply code causing a success or failure, you must call - * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode } after - * a success or failure. - *

- * You should keep in mind that the SMTP server may choose to prematurely - * close a connection for various reasons. The SMTPClient class will detect a - * premature SMTP server connection closing when it receives a - * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the method encountering that reply will throw - * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * . - * SMTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by SMTPClient. Before disconnecting, you may check - * the last reply code and text with - * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode }, - * {@link org.apache.commons.net.smtp.SMTP#getReplyString getReplyString }, - * and - * {@link org.apache.commons.net.smtp.SMTP#getReplyStrings getReplyStrings}. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- *

- * @author Daniel F. Savarese - * @see SMTP - * @see SimpleSMTPHeader - * @see RelayPath - * @see SMTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - ***/ - -public class SMTPClient extends SMTP -{ - - /** - * Default SMTPClient constructor. Creates a new SMTPClient instance. - */ - public SMTPClient() { } - - /** - * Overloaded constructor that takes an encoding specification - * @param encoding The encoding to use - * @since 2.0 - */ - public SMTPClient(String encoding) { - super(encoding); - } - - - /*** - * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) - * does not complete the entire sequence of SMTP commands to complete a - * transaction. These types of commands require some action by the - * programmer after the reception of a positive intermediate command. - * After the programmer's code completes its actions, it must call this - * method to receive the completion reply from the server and verify the - * success of the entire transaction. - *

- * For example, - *

-     * writer = client.sendMessage();
-     * if(writer == null) // failure
-     *   return false;
-     * header =
-     *  new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo");
-     * writer.write(header.toString());
-     * writer.write("This is just a test");
-     * writer.close();
-     * if(!client.completePendingCommand()) // failure
-     *   return false;
-     * 
- *

- * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean completePendingCommand() throws IOException - { - return SMTPReply.isPositiveCompletion(getReply()); - } - - - /*** - * Login to the SMTP server by sending the HELO command with the - * given hostname as an argument. Before performing any mail commands, - * you must first login. - *

- * @param hostname The hostname with which to greet the SMTP server. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean login(String hostname) throws IOException - { - return SMTPReply.isPositiveCompletion(helo(hostname)); - } - - - /*** - * Login to the SMTP server by sending the HELO command with the - * client hostname as an argument. Before performing any mail commands, - * you must first login. - *

- * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean login() throws IOException - { - String name; - InetAddress host; - - host = getLocalAddress(); - name = host.getHostName(); - - if (name == null) - return false; - - return SMTPReply.isPositiveCompletion(helo(name)); - } - - - /*** - * Set the sender of a message using the SMTP MAIL command, specifying - * a reverse relay path. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param path The reverse relay path pointing back to the sender. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean setSender(RelayPath path) throws IOException - { - return SMTPReply.isPositiveCompletion(mail(path.toString())); - } - - - /*** - * Set the sender of a message using the SMTP MAIL command, specifying - * the sender's email address. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param address The sender's email address. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean setSender(String address) throws IOException - { - return SMTPReply.isPositiveCompletion(mail("<" + address + ">")); - } - - - /*** - * Add a recipient for a message using the SMTP RCPT command, specifying - * a forward relay path. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param path The forward relay path pointing to the recipient. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean addRecipient(RelayPath path) throws IOException - { - return SMTPReply.isPositiveCompletion(rcpt(path.toString())); - } - - - /*** - * Add a recipient for a message using the SMTP RCPT command, the - * recipient's email address. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param address The recipient's email address. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean addRecipient(String address) throws IOException - { - return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">")); - } - - - - /*** - * Send the SMTP DATA command in preparation to send an email message. - * This method returns a DotTerminatedMessageWriter instance to which - * the message can be written. Null is returned if the DATA command - * fails. - *

- * You must not issue any commands to the SMTP server (i.e., call any - * (other methods) until you finish writing to the returned Writer - * instance and close it. The SMTP protocol uses the same stream for - * issuing commands as it does for returning results. Therefore the - * returned Writer actually writes directly to the SMTP connection. - * After you close the writer, you can execute new commands. If you - * do not follow these requirements your program will not work properly. - *

- * You can use the provided - * {@link org.apache.commons.net.smtp.SimpleSMTPHeader} - * class to construct a bare minimum header. - * To construct more complicated headers you should - * refer to RFC 822. When the Java Mail API is finalized, you will be - * able to use it to compose fully compliant Internet text messages. - * The DotTerminatedMessageWriter takes care of doubling line-leading - * dots and ending the message with a single dot upon closing, so all - * you have to worry about is writing the header and the message. - *

- * Upon closing the returned Writer, you need to call - * {@link #completePendingCommand completePendingCommand() } - * to finalize the transaction and verify its success or failure from - * the server reply. - *

- * @return A DotTerminatedMessageWriter to which the message (including - * header) can be written. Returns null if the command fails. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public Writer sendMessageData() throws IOException - { - if (!SMTPReply.isPositiveIntermediate(data())) - return null; - - return new DotTerminatedMessageWriter(_writer); - } - - - /*** - * A convenience method for sending short messages. This method fetches - * the Writer returned by {@link #sendMessageData sendMessageData() } - * and writes the specified String to it. After writing the message, - * this method calls {@link #completePendingCommand completePendingCommand() } - * to finalize the transaction and returns - * its success or failure. - *

- * @param message The short email message to send. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean sendShortMessageData(String message) throws IOException - { - Writer writer; - - writer = sendMessageData(); - - if (writer == null) - return false; - - writer.write(message); - writer.close(); - - return completePendingCommand(); - } - - - /*** - * A convenience method for a sending short email without having to - * explicitly set the sender and recipient(s). This method - * sets the sender and recipient using - * {@link #setSender setSender } and - * {@link #addRecipient addRecipient }, and then sends the - * message using {@link #sendShortMessageData sendShortMessageData }. - *

- * @param sender The email address of the sender. - * @param recipient The email address of the recipient. - * @param message The short email message to send. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean sendSimpleMessage(String sender, String recipient, - String message) - throws IOException - { - if (!setSender(sender)) - return false; - - if (!addRecipient(recipient)) - return false; - - return sendShortMessageData(message); - } - - - - /*** - * A convenience method for a sending short email without having to - * explicitly set the sender and recipient(s). This method - * sets the sender and recipients using - * {@link #setSender setSender } and - * {@link #addRecipient addRecipient }, and then sends the - * message using {@link #sendShortMessageData sendShortMessageData }. - *

- * @param sender The email address of the sender. - * @param recipients An array of recipient email addresses. - * @param message The short email message to send. - * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean sendSimpleMessage(String sender, String[] recipients, - String message) - throws IOException - { - boolean oneSuccess = false; - int count; - - if (!setSender(sender)) - return false; - - for (count = 0; count < recipients.length; count++) - { - if (addRecipient(recipients[count])) - oneSuccess = true; - } - - if (!oneSuccess) - return false; - - return sendShortMessageData(message); - } - - - /*** - * Logout of the SMTP server by sending the QUIT command. - *

- * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean logout() throws IOException - { - return SMTPReply.isPositiveCompletion(quit()); - } - - - - /*** - * Aborts the current mail transaction, resetting all server stored - * sender, recipient, and mail data, cleaing all buffers and tables. - *

- * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean reset() throws IOException - { - return SMTPReply.isPositiveCompletion(rset()); - } - - - /*** - * Verify that a username or email address is valid, i.e., that mail - * can be delivered to that mailbox on the server. - *

- * @param username The username or email address to validate. - * @return True if the username is valid, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean verify(String username) throws IOException - { - int result; - - result = vrfy(username); - - return (result == SMTPReply.ACTION_OK || - result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD); - } - - - /*** - * Fetches the system help information from the server and returns the - * full string. - *

- * @return The system help string obtained from the server. null if the - * information could not be obtained. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String listHelp() throws IOException - { - if (SMTPReply.isPositiveCompletion(help())) - return getReplyString(); - return null; - } - - - /*** - * Fetches the help information for a given command from the server and - * returns the full string. - *

- * @param command The command on which to ask for help. - * @return The command help string obtained from the server. null if the - * information could not be obtained. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public String listHelp(String command) throws IOException - { - if (SMTPReply.isPositiveCompletion(help(command))) - return getReplyString(); - return null; - } - - - /*** - * Sends a NOOP command to the SMTP server. This is useful for preventing - * server timeouts. - *

- * @return True if successfully completed, false if not. - * @exception SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @exception IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - ***/ - public boolean sendNoOp() throws IOException - { - return SMTPReply.isPositiveCompletion(noop()); - } - -} diff --git a/org/apache/commons/net/smtp/SMTPCommand.java b/org/apache/commons/net/smtp/SMTPCommand.java deleted file mode 100644 index 04dbf99..0000000 --- a/org/apache/commons/net/smtp/SMTPCommand.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -/*** - * SMTPCommand stores a set of constants for SMTP command codes. To interpret - * the meaning of the codes, familiarity with RFC 821 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 821. For those who think in terms of the actual SMTP commands, - * a set of constants such as {@link #HELO HELO } are provided - * where the constant name is the same as the SMTP command. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class SMTPCommand -{ - - - public static final int HELO = 0; - public static final int MAIL = 1; - public static final int RCPT = 2; - public static final int DATA = 3; - public static final int SEND = 4; - public static final int SOML = 5; - public static final int SAML = 6; - public static final int RSET = 7; - public static final int VRFY = 8; - public static final int EXPN = 9; - public static final int HELP = 10; - public static final int NOOP = 11; - public static final int TURN = 12; - public static final int QUIT = 13; - - public static final int HELLO = HELO; - public static final int LOGIN = HELO; - public static final int MAIL_FROM = MAIL; - public static final int RECIPIENT = RCPT; - public static final int SEND_MESSAGE_DATA = DATA; - public static final int SEND_FROM = SEND; - public static final int SEND_OR_MAIL_FROM = SOML; - public static final int SEND_AND_MAIL_FROM = SAML; - public static final int RESET = RSET; - public static final int VERIFY = VRFY; - public static final int EXPAND = EXPN; - // public static final int HELP = HELP; - // public static final int NOOP = NOOP; - // public static final int TURN = TURN; - // public static final int QUIT = QUIT; - public static final int LOGOUT = QUIT; - - // Cannot be instantiated - private SMTPCommand() - {} - - static final String[] _commands = { - "HELO", "MAIL FROM:", "RCPT TO:", "DATA", "SEND FROM:", "SOML FROM:", - "SAML FROM:", "RSET", "VRFY", "EXPN", "HELP", "NOOP", "TURN", "QUIT" - }; - - - /*** - * Retrieve the SMTP protocol command string corresponding to a specified - * command code. - *

- * @param command The command code. - * @return The SMTP protcol command string corresponding to a specified - * command code. - ***/ - public static final String getCommand(int command) - { - return _commands[command]; - } - -} diff --git a/org/apache/commons/net/smtp/SMTPConnectionClosedException.java b/org/apache/commons/net/smtp/SMTPConnectionClosedException.java deleted file mode 100644 index f9a5762..0000000 --- a/org/apache/commons/net/smtp/SMTPConnectionClosedException.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.IOException; - -/*** - * SMTPConnectionClosedException is used to indicate the premature or - * unexpected closing of an SMTP connection resulting from a - * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } - * response (SMTP reply code 421) to a - * failed SMTP command. This exception is derived from IOException and - * therefore may be caught either as an IOException or specifically as an - * SMTPConnectionClosedException. - *

- *

- * @author Daniel F. Savarese - * @see SMTP - * @see SMTPClient - ***/ - -public final class SMTPConnectionClosedException extends IOException -{ - - /*** Constructs a SMTPConnectionClosedException with no message ***/ - public SMTPConnectionClosedException() - { - super(); - } - - /*** - * Constructs a SMTPConnectionClosedException with a specified message. - *

- * @param message The message explaining the reason for the exception. - ***/ - public SMTPConnectionClosedException(String message) - { - super(message); - } - -} diff --git a/org/apache/commons/net/smtp/SMTPReply.java b/org/apache/commons/net/smtp/SMTPReply.java deleted file mode 100644 index 45fd7c8..0000000 --- a/org/apache/commons/net/smtp/SMTPReply.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -/*** - * SMTPReply stores a set of constants for SMTP reply codes. To interpret - * the meaning of the codes, familiarity with RFC 821 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 821. For those who think in terms of the actual reply code values, - * a set of CODE_NUM constants are provided where NUM is the numerical value - * of the code. - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class SMTPReply -{ - - public static final int CODE_211 = 211; - public static final int CODE_214 = 214; - public static final int CODE_215 = 215; - public static final int CODE_220 = 220; - public static final int CODE_221 = 221; - public static final int CODE_250 = 250; - public static final int CODE_251 = 251; - public static final int CODE_354 = 354; - public static final int CODE_421 = 421; - public static final int CODE_450 = 450; - public static final int CODE_451 = 451; - public static final int CODE_452 = 452; - public static final int CODE_500 = 500; - public static final int CODE_501 = 501; - public static final int CODE_502 = 502; - public static final int CODE_503 = 503; - public static final int CODE_504 = 504; - public static final int CODE_550 = 550; - public static final int CODE_551 = 551; - public static final int CODE_552 = 552; - public static final int CODE_553 = 553; - public static final int CODE_554 = 554; - - public static final int SYSTEM_STATUS = CODE_211; - public static final int HELP_MESSAGE = CODE_214; - public static final int SERVICE_READY = CODE_220; - public static final int SERVICE_CLOSING_TRANSMISSION_CHANNEL = CODE_221; - public static final int ACTION_OK = CODE_250; - public static final int USER_NOT_LOCAL_WILL_FORWARD = CODE_251; - public static final int START_MAIL_INPUT = CODE_354; - public static final int SERVICE_NOT_AVAILABLE = CODE_421; - public static final int ACTION_NOT_TAKEN = CODE_450; - public static final int ACTION_ABORTED = CODE_451; - public static final int INSUFFICIENT_STORAGE = CODE_452; - public static final int UNRECOGNIZED_COMMAND = CODE_500; - public static final int SYNTAX_ERROR_IN_ARGUMENTS = CODE_501; - public static final int COMMAND_NOT_IMPLEMENTED = CODE_502; - public static final int BAD_COMMAND_SEQUENCE = CODE_503; - public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = CODE_504; - public static final int MAILBOX_UNAVAILABLE = CODE_550; - public static final int USER_NOT_LOCAL = CODE_551; - public static final int STORAGE_ALLOCATION_EXCEEDED = CODE_552; - public static final int MAILBOX_NAME_NOT_ALLOWED = CODE_553; - public static final int TRANSACTION_FAILED = CODE_554; - - // Cannot be instantiated - private SMTPReply() - {} - - /*** - * Determine if a reply code is a positive preliminary response. All - * codes beginning with a 1 are positive preliminary responses. - * Postitive preliminary responses are used to indicate tentative success. - * No further commands can be issued to the SMTP server after a positive - * preliminary response until a follow up response is received from the - * server. - *

- * Note: No SMTP commands defined in RFC 822 provide this - * type of reply. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive preliminary response, false - * if not. - ***/ - public static boolean isPositivePreliminary(int reply) - { - return (reply >= 100 && reply < 200); - } - - /*** - * Determine if a reply code is a positive completion response. All - * codes beginning with a 2 are positive completion responses. - * The SMTP server will send a positive completion response on the final - * successful completion of a command. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive completion response, false - * if not. - ***/ - public static boolean isPositiveCompletion(int reply) - { - return (reply >= 200 && reply < 300); - } - - /*** - * Determine if a reply code is a positive intermediate response. All - * codes beginning with a 3 are positive intermediate responses. - * The SMTP server will send a positive intermediate response on the - * successful completion of one part of a multi-part sequence of - * commands. For example, after a successful DATA command, a positive - * intermediate response will be sent to indicate that the server is - * ready to receive the message data. - *

- * @param reply The reply code to test. - * @return True if a reply code is a postive intermediate response, false - * if not. - ***/ - public static boolean isPositiveIntermediate(int reply) - { - return (reply >= 300 && reply < 400); - } - - /*** - * Determine if a reply code is a negative transient response. All - * codes beginning with a 4 are negative transient responses. - * The SMTP server will send a negative transient response on the - * failure of a command that can be reattempted with success. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative transient response, false - * if not. - ***/ - public static boolean isNegativeTransient(int reply) - { - return (reply >= 400 && reply < 500); - } - - /*** - * Determine if a reply code is a negative permanent response. All - * codes beginning with a 5 are negative permanent responses. - * The SMTP server will send a negative permanent response on the - * failure of a command that cannot be reattempted with success. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative permanent response, false - * if not. - ***/ - public static boolean isNegativePermanent(int reply) - { - return (reply >= 500 && reply < 600); - } - -} diff --git a/org/apache/commons/net/smtp/SimpleSMTPHeader.java b/org/apache/commons/net/smtp/SimpleSMTPHeader.java deleted file mode 100644 index ed0ea4d..0000000 --- a/org/apache/commons/net/smtp/SimpleSMTPHeader.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -/*** - * This class is used to construct a bare minimum - * acceptable header for an email message. To construct more - * complicated headers you should refer to RFC 822. When the - * Java Mail API is finalized, you will be - * able to use it to compose fully compliant Internet text messages. - *

- * The main purpose of the class is to faciliatate the mail sending - * process, by relieving the programmer from having to explicitly format - * a simple message header. For example: - *

- * writer = client.sendMessageData();
- * if(writer == null) // failure
- *   return false;
- * header =
- *    new SimpleSMTPHeader("foobar@foo.com", "foo@bar.com" "Just testing");
- * header.addCC("bar@foo.com");
- * header.addHeaderField("Organization", "Foobar, Inc.");
- * writer.write(header.toString());
- * writer.write("This is just a test");
- * writer.close();
- * if(!client.completePendingCommand()) // failure
- *   return false;
- * 
- *

- *

- * @author Daniel F. Savarese - * @see SMTPClient - ***/ - -public class SimpleSMTPHeader -{ - private String __subject, __from, __to; - private StringBuffer __headerFields, __cc; - - /*** - * Creates a new SimpleSMTPHeader instance initialized with the given - * from, to, and subject header field values. - *

- * @param from The value of the From: header field. This - * should be the sender's email address. - * @param to The value of the To: header field. This - * should be the recipient's email address. - * @param subject The value of the Subject: header field. - * This should be the subject of the message. - ***/ - public SimpleSMTPHeader(String from, String to, String subject) - { - __to = to; - __from = from; - __subject = subject; - __headerFields = new StringBuffer(); - __cc = null; - } - - /*** - * Adds an arbitrary header field with the given value to the article - * header. These headers will be written before the From, To, Subject, and - * Cc fields when the SimpleSMTPHeader is convertered to a string. - * An example use would be: - *

-     * header.addHeaderField("Organization", "Foobar, Inc.");
-     * 
- *

- * @param headerField The header field to add, not including the colon. - * @param value The value of the added header field. - ***/ - public void addHeaderField(String headerField, String value) - { - __headerFields.append(headerField); - __headerFields.append(": "); - __headerFields.append(value); - __headerFields.append('\n'); - } - - - /*** - * Add an email address to the CC (carbon copy or courtesy copy) list. - *

- * @param address The email address to add to the CC list. - ***/ - public void addCC(String address) - { - if (__cc == null) - __cc = new StringBuffer(); - else - __cc.append(", "); - - __cc.append(address); - } - - - /*** - * Converts the SimpleSMTPHeader to a properly formatted header in - * the form of a String, including the blank line used to separate - * the header from the article body. The header fields CC and Subject - * are only included when they are non-null. - *

- * @return The message header in the form of a String. - ***/ - @Override - public String toString() - { - StringBuffer header = new StringBuffer(); - - if (__headerFields.length() > 0) - header.append(__headerFields.toString()); - - header.append("From: "); - header.append(__from); - header.append("\nTo: "); - header.append(__to); - - if (__cc != null) - { - header.append("\nCc: "); - header.append(__cc.toString()); - } - - if (__subject != null) - { - header.append("\nSubject: "); - header.append(__subject); - } - - header.append('\n'); - header.append('\n'); - - return header.toString(); - } -} - - - diff --git a/org/apache/commons/net/telnet/EchoOptionHandler.java b/org/apache/commons/net/telnet/EchoOptionHandler.java deleted file mode 100644 index 8c43f85..0000000 --- a/org/apache/commons/net/telnet/EchoOptionHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * Implements the telnet echo option RFC 857. - *

- * @author Bruno D'Avanzo - ***/ -public class EchoOptionHandler extends TelnetOptionHandler -{ - /*** - * Constructor for the EchoOptionHandler. Allows defining desired - * initial setting for local/remote activation of this option and - * behaviour in case a local/remote activation request for this - * option is received. - *

- * @param initlocal - if set to true, a WILL is sent upon connection. - * @param initremote - if set to true, a DO is sent upon connection. - * @param acceptlocal - if set to true, any DO request is accepted. - * @param acceptremote - if set to true, any WILL request is accepted. - ***/ - public EchoOptionHandler(boolean initlocal, boolean initremote, - boolean acceptlocal, boolean acceptremote) - { - super(TelnetOption.ECHO, initlocal, initremote, - acceptlocal, acceptremote); - } - - /*** - * Constructor for the EchoOptionHandler. Initial and accept - * behaviour flags are set to false - ***/ - public EchoOptionHandler() - { - super(TelnetOption.ECHO, false, false, false, false); - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @param suboptionData - the sequence received, whithout IAC SB & IAC SE - * @param suboptionLength - the length of data in suboption_data - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] answerSubnegotiation(int suboptionData[], - int suboptionLength) - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationLocal() - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationRemote() - { - return null; - } -} diff --git a/org/apache/commons/net/telnet/InvalidTelnetOptionException.java b/org/apache/commons/net/telnet/InvalidTelnetOptionException.java deleted file mode 100644 index 740d185..0000000 --- a/org/apache/commons/net/telnet/InvalidTelnetOptionException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * The InvalidTelnetOptionException is the exception that is - * thrown whenever a TelnetOptionHandler with an invlaid - * option code is registered in TelnetClient with addOptionHandler. - *

- * @author Bruno D'Avanzo - ***/ -public class InvalidTelnetOptionException extends Exception -{ - - /*** - * Option code - ***/ - private int optionCode = -1; - - /*** - * Error message - ***/ - private String msg; - - /*** - * Constructor for the exception. - *

- * @param message - Error message. - * @param optcode - Option code. - ***/ - public InvalidTelnetOptionException(String message, int optcode) - { - optionCode = optcode; - msg = message; - } - - /*** - * Gets the error message of ths exception. - *

- * @return the error message. - ***/ - @Override - public String getMessage() - { - return (msg + ": " + optionCode); - } -} diff --git a/org/apache/commons/net/telnet/SimpleOptionHandler.java b/org/apache/commons/net/telnet/SimpleOptionHandler.java deleted file mode 100644 index 3395508..0000000 --- a/org/apache/commons/net/telnet/SimpleOptionHandler.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * Simple option handler that can be used for options - * that don't require subnegotiation. - *

- * @author Bruno D'Avanzo - ***/ -public class SimpleOptionHandler extends TelnetOptionHandler -{ - /*** - * Constructor for the SimpleOptionHandler. Allows defining desired - * initial setting for local/remote activation of this option and - * behaviour in case a local/remote activation request for this - * option is received. - *

- * @param optcode - option code. - * @param initlocal - if set to true, a WILL is sent upon connection. - * @param initremote - if set to true, a DO is sent upon connection. - * @param acceptlocal - if set to true, any DO request is accepted. - * @param acceptremote - if set to true, any WILL request is accepted. - ***/ - public SimpleOptionHandler(int optcode, - boolean initlocal, - boolean initremote, - boolean acceptlocal, - boolean acceptremote) - { - super(optcode, initlocal, initremote, - acceptlocal, acceptremote); - } - - /*** - * Constructor for the SimpleOptionHandler. Initial and accept - * behaviour flags are set to false - *

- * @param optcode - option code. - ***/ - public SimpleOptionHandler(int optcode) - { - super(optcode, false, false, false, false); - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @param suboptionData - the sequence received, whithout IAC SB & IAC SE - * @param suboptionLength - the length of data in suboption_data - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationLocal() - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationRemote() - { - return null; - } -} diff --git a/org/apache/commons/net/telnet/SuppressGAOptionHandler.java b/org/apache/commons/net/telnet/SuppressGAOptionHandler.java deleted file mode 100644 index aa18452..0000000 --- a/org/apache/commons/net/telnet/SuppressGAOptionHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * Implements the telnet suppress go ahead option RFC 858. - *

- * @author Bruno D'Avanzo - ***/ -public class SuppressGAOptionHandler extends TelnetOptionHandler -{ - /*** - * Constructor for the SuppressGAOptionHandler. Allows defining desired - * initial setting for local/remote activation of this option and - * behaviour in case a local/remote activation request for this - * option is received. - *

- * @param initlocal - if set to true, a WILL is sent upon connection. - * @param initremote - if set to true, a DO is sent upon connection. - * @param acceptlocal - if set to true, any DO request is accepted. - * @param acceptremote - if set to true, any WILL request is accepted. - ***/ - public SuppressGAOptionHandler(boolean initlocal, boolean initremote, - boolean acceptlocal, boolean acceptremote) - { - super(TelnetOption.SUPPRESS_GO_AHEAD, initlocal, initremote, - acceptlocal, acceptremote); - } - - /*** - * Constructor for the SuppressGAOptionHandler. Initial and accept - * behaviour flags are set to false - ***/ - public SuppressGAOptionHandler() - { - super(TelnetOption.SUPPRESS_GO_AHEAD, false, false, false, false); - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @param suboptionData - the sequence received, whithout IAC SB & IAC SE - * @param suboptionLength - the length of data in suboption_data - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationLocal() - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationRemote() - { - return null; - } -} diff --git a/org/apache/commons/net/telnet/Telnet.java b/org/apache/commons/net/telnet/Telnet.java deleted file mode 100644 index c05b563..0000000 --- a/org/apache/commons/net/telnet/Telnet.java +++ /dev/null @@ -1,1317 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.OutputStream; -import java.io.IOException; -import org.apache.commons.net.SocketClient; - -/** - * @author Daniel F. Savarese - * @author Bruno D'Avanzo - */ - -class Telnet extends SocketClient -{ - static final boolean debug = /*true;*/ false; - - static final boolean debugoptions = /*true;*/ false; - - static final byte[] _COMMAND_DO = { - (byte)TelnetCommand.IAC, (byte)TelnetCommand.DO - }; - - static final byte[] _COMMAND_DONT = { - (byte)TelnetCommand.IAC, (byte)TelnetCommand.DONT - }; - - static final byte[] _COMMAND_WILL = { - (byte)TelnetCommand.IAC, (byte)TelnetCommand.WILL - }; - - static final byte[] _COMMAND_WONT = { - (byte)TelnetCommand.IAC, (byte)TelnetCommand.WONT - }; - - static final byte[] _COMMAND_SB = { - (byte)TelnetCommand.IAC, (byte)TelnetCommand.SB - }; - - static final byte[] _COMMAND_SE = { - (byte)TelnetCommand.IAC, (byte)TelnetCommand.SE - }; - - static final int _WILL_MASK = 0x01, _DO_MASK = 0x02, - _REQUESTED_WILL_MASK = 0x04, _REQUESTED_DO_MASK = 0x08; - - /* public */ - static final int DEFAULT_PORT = 23; - - int[] _doResponse, _willResponse, _options; - - /* TERMINAL-TYPE option (start)*/ - /*** - * Terminal type option - ***/ - protected static final int TERMINAL_TYPE = 24; - - /*** - * Send (for subnegotiation) - ***/ - protected static final int TERMINAL_TYPE_SEND = 1; - - /*** - * Is (for subnegotiation) - ***/ - protected static final int TERMINAL_TYPE_IS = 0; - - /*** - * Is sequence (for subnegotiation) - ***/ - static final byte[] _COMMAND_IS = { - (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS - }; - - /*** - * Terminal type - ***/ - private String terminalType = null; - /* TERMINAL-TYPE option (end)*/ - - /* open TelnetOptionHandler functionality (start)*/ - /*** - * Array of option handlers - ***/ - private TelnetOptionHandler optionHandlers[]; - - /* open TelnetOptionHandler functionality (end)*/ - - /* Code Section added for supporting AYT (start)*/ - /*** - * AYT sequence - ***/ - static final byte[] _COMMAND_AYT = { - (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT - }; - - /*** - * monitor to wait for AYT - ***/ - private Object aytMonitor = new Object(); - - /*** - * flag for AYT - ***/ - private boolean aytFlag = true; - /* Code Section added for supporting AYT (end)*/ - - /*** - * The stream on which to spy - ***/ - private OutputStream spyStream = null; - - /*** - * The notification handler - ***/ - private TelnetNotificationHandler __notifhand = null; - /*** - * Empty Constructor - ***/ - Telnet() - { - setDefaultPort(DEFAULT_PORT); - _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; - _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; - _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; - optionHandlers = - new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; - } - - /* TERMINAL-TYPE option (start)*/ - /*** - * This constructor lets you specify the terminal type. - *

- * @param termtype - terminal type to be negotiated (ej. VT100) - ***/ - Telnet(String termtype) - { - setDefaultPort(DEFAULT_PORT); - _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; - _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; - _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; - terminalType = termtype; - optionHandlers = - new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; - } - /* TERMINAL-TYPE option (end)*/ - - /*** - * Looks for the state of the option. - *

- * @return returns true if a will has been acknowledged - *

- * @param option - option code to be looked up. - ***/ - boolean _stateIsWill(int option) - { - return ((_options[option] & _WILL_MASK) != 0); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a wont has been acknowledged - *

- * @param option - option code to be looked up. - ***/ - boolean _stateIsWont(int option) - { - return !_stateIsWill(option); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a do has been acknowledged - *

- * @param option - option code to be looked up. - ***/ - boolean _stateIsDo(int option) - { - return ((_options[option] & _DO_MASK) != 0); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a dont has been acknowledged - *

- * @param option - option code to be looked up. - ***/ - boolean _stateIsDont(int option) - { - return !_stateIsDo(option); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a will has been reuqested - *

- * @param option - option code to be looked up. - ***/ - boolean _requestedWill(int option) - { - return ((_options[option] & _REQUESTED_WILL_MASK) != 0); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a wont has been reuqested - *

- * @param option - option code to be looked up. - ***/ - boolean _requestedWont(int option) - { - return !_requestedWill(option); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a do has been reuqested - *

- * @param option - option code to be looked up. - ***/ - boolean _requestedDo(int option) - { - return ((_options[option] & _REQUESTED_DO_MASK) != 0); - } - - /*** - * Looks for the state of the option. - *

- * @return returns true if a dont has been reuqested - *

- * @param option - option code to be looked up. - ***/ - boolean _requestedDont(int option) - { - return !_requestedDo(option); - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setWill(int option) - { - _options[option] |= _WILL_MASK; - - /* open TelnetOptionHandler functionality (start)*/ - if (_requestedWill(option)) - { - if (optionHandlers[option] != null) - { - optionHandlers[option].setWill(true); - - int subneg[] = - optionHandlers[option].startSubnegotiationLocal(); - - if (subneg != null) - { - try - { - _sendSubnegotiation(subneg); - } - catch (IOException e) - { - System.err.println( - "Exception in option subnegotiation" - + e.getMessage()); - } - } - } - } - /* open TelnetOptionHandler functionality (end)*/ - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setDo(int option) - { - _options[option] |= _DO_MASK; - - /* open TelnetOptionHandler functionality (start)*/ - if (_requestedDo(option)) - { - if (optionHandlers[option] != null) - { - optionHandlers[option].setDo(true); - - int subneg[] = - optionHandlers[option].startSubnegotiationRemote(); - - if (subneg != null) - { - try - { - _sendSubnegotiation(subneg); - } - catch (IOException e) - { - System.err.println("Exception in option subnegotiation" - + e.getMessage()); - } - } - } - } - /* open TelnetOptionHandler functionality (end)*/ - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setWantWill(int option) - { - _options[option] |= _REQUESTED_WILL_MASK; - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setWantDo(int option) - { - _options[option] |= _REQUESTED_DO_MASK; - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setWont(int option) - { - _options[option] &= ~_WILL_MASK; - - /* open TelnetOptionHandler functionality (start)*/ - if (optionHandlers[option] != null) - { - optionHandlers[option].setWill(false); - } - /* open TelnetOptionHandler functionality (end)*/ - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setDont(int option) - { - _options[option] &= ~_DO_MASK; - - /* open TelnetOptionHandler functionality (start)*/ - if (optionHandlers[option] != null) - { - optionHandlers[option].setDo(false); - } - /* open TelnetOptionHandler functionality (end)*/ - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setWantWont(int option) - { - _options[option] &= ~_REQUESTED_WILL_MASK; - } - - /*** - * Sets the state of the option. - *

- * @param option - option code to be set. - ***/ - void _setWantDont(int option) - { - _options[option] &= ~_REQUESTED_DO_MASK; - } - - /** - * Processes a DO request. - * - * @param option - option code to be set. - * @throws IOException - Exception in I/O. - **/ - void _processDo(int option) throws IOException - { - if (debugoptions) - { - System.err.println("RECEIVED DO: " - + TelnetOption.getOption(option)); - } - - if (__notifhand != null) - { - __notifhand.receivedNegotiation( - TelnetNotificationHandler.RECEIVED_DO, - option); - } - - boolean acceptNewState = false; - - - /* open TelnetOptionHandler functionality (start)*/ - if (optionHandlers[option] != null) - { - acceptNewState = optionHandlers[option].getAcceptLocal(); - } - else - { - /* open TelnetOptionHandler functionality (end)*/ - /* TERMINAL-TYPE option (start)*/ - if (option == TERMINAL_TYPE) - { - if ((terminalType != null) && (terminalType.length() > 0)) - { - acceptNewState = true; - } - } - /* TERMINAL-TYPE option (end)*/ - /* open TelnetOptionHandler functionality (start)*/ - } - /* open TelnetOptionHandler functionality (end)*/ - - if (_willResponse[option] > 0) - { - --_willResponse[option]; - if (_willResponse[option] > 0 && _stateIsWill(option)) - { - --_willResponse[option]; - } - } - - if (_willResponse[option] == 0) - { - if (_requestedWont(option)) - { - - switch (option) - { - - default: - break; - - } - - - if (acceptNewState) - { - _setWantWill(option); - _sendWill(option); - } - else - { - ++_willResponse[option]; - _sendWont(option); - } - } - else - { - // Other end has acknowledged option. - - switch (option) - { - - default: - break; - - } - - } - } - - _setWill(option); - } - - /** - * Processes a DONT request. - * - * @param option - option code to be set. - * @throws IOException - Exception in I/O. - **/ - void _processDont(int option) throws IOException - { - if (debugoptions) - { - System.err.println("RECEIVED DONT: " - + TelnetOption.getOption(option)); - } - if (__notifhand != null) - { - __notifhand.receivedNegotiation( - TelnetNotificationHandler.RECEIVED_DONT, - option); - } - if (_willResponse[option] > 0) - { - --_willResponse[option]; - if (_willResponse[option] > 0 && _stateIsWont(option)) - { - --_willResponse[option]; - } - } - - if (_willResponse[option] == 0 && _requestedWill(option)) - { - - switch (option) - { - - default: - break; - - } - - /* FIX for a BUG in the negotiation (start)*/ - if ((_stateIsWill(option)) || (_requestedWill(option))) - { - _sendWont(option); - } - - _setWantWont(option); - /* FIX for a BUG in the negotiation (end)*/ - } - - _setWont(option); - } - - - /** - * Processes a WILL request. - * - * @param option - option code to be set. - * @throws IOException - Exception in I/O. - **/ - void _processWill(int option) throws IOException - { - if (debugoptions) - { - System.err.println("RECEIVED WILL: " - + TelnetOption.getOption(option)); - } - - if (__notifhand != null) - { - __notifhand.receivedNegotiation( - TelnetNotificationHandler.RECEIVED_WILL, - option); - } - - boolean acceptNewState = false; - - /* open TelnetOptionHandler functionality (start)*/ - if (optionHandlers[option] != null) - { - acceptNewState = optionHandlers[option].getAcceptRemote(); - } - /* open TelnetOptionHandler functionality (end)*/ - - if (_doResponse[option] > 0) - { - --_doResponse[option]; - if (_doResponse[option] > 0 && _stateIsDo(option)) - { - --_doResponse[option]; - } - } - - if (_doResponse[option] == 0 && _requestedDont(option)) - { - - switch (option) - { - - default: - break; - - } - - - if (acceptNewState) - { - _setWantDo(option); - _sendDo(option); - } - else - { - ++_doResponse[option]; - _sendDont(option); - } - } - - _setDo(option); - } - - /** - * Processes a WONT request. - * - * @param option - option code to be set. - * @throws IOException - Exception in I/O. - **/ - void _processWont(int option) throws IOException - { - if (debugoptions) - { - System.err.println("RECEIVED WONT: " - + TelnetOption.getOption(option)); - } - - if (__notifhand != null) - { - __notifhand.receivedNegotiation( - TelnetNotificationHandler.RECEIVED_WONT, - option); - } - - if (_doResponse[option] > 0) - { - --_doResponse[option]; - if (_doResponse[option] > 0 && _stateIsDont(option)) - { - --_doResponse[option]; - } - } - - if (_doResponse[option] == 0 && _requestedDo(option)) - { - - switch (option) - { - - default: - break; - - } - - /* FIX for a BUG in the negotiation (start)*/ - if ((_stateIsDo(option)) || (_requestedDo(option))) - { - _sendDont(option); - } - - _setWantDont(option); - /* FIX for a BUG in the negotiation (end)*/ - } - - _setDont(option); - } - - /* TERMINAL-TYPE option (start)*/ - /** - * Processes a suboption negotiation. - * - * @param suboption - subnegotiation data received - * @param suboptionLength - length of data received - * @throws IOException - Exception in I/O. - **/ - void _processSuboption(int suboption[], int suboptionLength) - throws IOException - { - if (debug) - { - System.err.println("PROCESS SUBOPTION."); - } - - /* open TelnetOptionHandler functionality (start)*/ - if (suboptionLength > 0) - { - if (optionHandlers[suboption[0]] != null) - { - int responseSuboption[] = - optionHandlers[suboption[0]].answerSubnegotiation(suboption, - suboptionLength); - _sendSubnegotiation(responseSuboption); - } - else - { - if (suboptionLength > 1) - { - if (debug) - { - for (int ii = 0; ii < suboptionLength; ii++) - { - System.err.println("SUB[" + ii + "]: " - + suboption[ii]); - } - } - if ((suboption[0] == TERMINAL_TYPE) - && (suboption[1] == TERMINAL_TYPE_SEND)) - { - _sendTerminalType(); - } - } - } - } - /* open TelnetOptionHandler functionality (end)*/ - } - - /*** - * Sends terminal type information. - *

- * @throws IOException - Exception in I/O. - ***/ - final synchronized void _sendTerminalType() - throws IOException - { - if (debug) - { - System.err.println("SEND TERMINAL-TYPE: " + terminalType); - } - if (terminalType != null) - { - _output_.write(_COMMAND_SB); - _output_.write(_COMMAND_IS); - _output_.write(terminalType.getBytes()); - _output_.write(_COMMAND_SE); - _output_.flush(); - } - } - - /* TERMINAL-TYPE option (end)*/ - - /* open TelnetOptionHandler functionality (start)*/ - /** - * Manages subnegotiation for Terminal Type. - * - * @param subn - subnegotiation data to be sent - * @throws IOException - Exception in I/O. - **/ - final synchronized void _sendSubnegotiation(int subn[]) - throws IOException - { - if (debug) - { - System.err.println("SEND SUBNEGOTIATION: "); - if (subn != null) - { - for (int ii = 0; ii < subn.length; ii++) - { - System.err.println("subn[" + ii + "]=" + subn[ii]); - } - } - } - if (subn != null) - { - byte byteresp[] = new byte[subn.length]; - for (int ii = 0; ii < subn.length; ii++) - { - byteresp[ii] = (byte) subn[ii]; - } - - _output_.write(_COMMAND_SB); - _output_.write(byteresp); - _output_.write(_COMMAND_SE); - - /* Code Section added for sending the negotiation ASAP (start)*/ - _output_.flush(); - /* Code Section added for sending the negotiation ASAP (end)*/ - } - } - /* open TelnetOptionHandler functionality (end)*/ - - /* Code Section added for supporting AYT (start)*/ - /*** - * Processes the response of an AYT - ***/ - final synchronized void _processAYTResponse() - { - if (!aytFlag) - { - synchronized (aytMonitor) - { - aytFlag = true; - try - { - aytMonitor.notifyAll(); - } - catch (IllegalMonitorStateException e) - { - System.err.println("Exception notifying:" + e.getMessage()); - } - } - } - } - /* Code Section added for supporting AYT (end)*/ - - /*** - * Called upon connection. - *

- * @throws IOException - Exception in I/O. - ***/ - @Override - protected void _connectAction_() throws IOException - { - /* (start). BUGFIX: clean the option info for each connection*/ - for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) - { - _doResponse[ii] = 0; - _willResponse[ii] = 0; - _options[ii] = 0; - if (optionHandlers[ii] != null) - { - optionHandlers[ii].setDo(false); - optionHandlers[ii].setWill(false); - } - } - /* (end). BUGFIX: clean the option info for each connection*/ - - super._connectAction_(); - _input_ = new BufferedInputStream(_input_); - _output_ = new BufferedOutputStream(_output_); - - /* open TelnetOptionHandler functionality (start)*/ - for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) - { - if (optionHandlers[ii] != null) - { - if (optionHandlers[ii].getInitLocal()) - { - try - { - _requestWill(optionHandlers[ii].getOptionCode()); - } - catch (IOException e) - { - System.err.println( - "Exception while initializing option: " - + e.getMessage()); - } - } - - if (optionHandlers[ii].getInitRemote()) - { - try - { - _requestDo(optionHandlers[ii].getOptionCode()); - } - catch (IOException e) - { - System.err.println( - "Exception while initializing option: " - + e.getMessage()); - } - } - } - } - /* open TelnetOptionHandler functionality (end)*/ - } - - /** - * Sends a DO. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _sendDo(int option) - throws IOException - { - if (debug || debugoptions) - { - System.err.println("DO: " + TelnetOption.getOption(option)); - } - _output_.write(_COMMAND_DO); - _output_.write(option); - - /* Code Section added for sending the negotiation ASAP (start)*/ - _output_.flush(); - /* Code Section added for sending the negotiation ASAP (end)*/ - } - - /** - * Requests a DO. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _requestDo(int option) - throws IOException - { - if ((_doResponse[option] == 0 && _stateIsDo(option)) - || _requestedDo(option)) - { - return ; - } - _setWantDo(option); - ++_doResponse[option]; - _sendDo(option); - } - - /** - * Sends a DONT. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _sendDont(int option) - throws IOException - { - if (debug || debugoptions) - { - System.err.println("DONT: " + TelnetOption.getOption(option)); - } - _output_.write(_COMMAND_DONT); - _output_.write(option); - - /* Code Section added for sending the negotiation ASAP (start)*/ - _output_.flush(); - /* Code Section added for sending the negotiation ASAP (end)*/ - } - - /** - * Requests a DONT. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _requestDont(int option) - throws IOException - { - if ((_doResponse[option] == 0 && _stateIsDont(option)) - || _requestedDont(option)) - { - return ; - } - _setWantDont(option); - ++_doResponse[option]; - _sendDont(option); - } - - - /** - * Sends a WILL. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _sendWill(int option) - throws IOException - { - if (debug || debugoptions) - { - System.err.println("WILL: " + TelnetOption.getOption(option)); - } - _output_.write(_COMMAND_WILL); - _output_.write(option); - - /* Code Section added for sending the negotiation ASAP (start)*/ - _output_.flush(); - /* Code Section added for sending the negotiation ASAP (end)*/ - } - - /** - * Requests a WILL. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _requestWill(int option) - throws IOException - { - if ((_willResponse[option] == 0 && _stateIsWill(option)) - || _requestedWill(option)) - { - return ; - } - _setWantWill(option); - ++_doResponse[option]; - _sendWill(option); - } - - /** - * Sends a WONT. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _sendWont(int option) - throws IOException - { - if (debug || debugoptions) - { - System.err.println("WONT: " + TelnetOption.getOption(option)); - } - _output_.write(_COMMAND_WONT); - _output_.write(option); - - /* Code Section added for sending the negotiation ASAP (start)*/ - _output_.flush(); - /* Code Section added for sending the negotiation ASAP (end)*/ - } - - /** - * Requests a WONT. - * - * @param option - Option code. - * @throws IOException - Exception in I/O. - **/ - final synchronized void _requestWont(int option) - throws IOException - { - if ((_willResponse[option] == 0 && _stateIsWont(option)) - || _requestedWont(option)) - { - return ; - } - _setWantWont(option); - ++_doResponse[option]; - _sendWont(option); - } - - /** - * Sends a byte. - * - * @param b - byte to send - * @throws IOException - Exception in I/O. - **/ - final synchronized void _sendByte(int b) - throws IOException - { - _output_.write(b); - - /* Code Section added for supporting spystreams (start)*/ - _spyWrite(b); - /* Code Section added for supporting spystreams (end)*/ - - } - - /* Code Section added for supporting AYT (start)*/ - /** - * Sends an Are You There sequence and waits for the result. - * - * @param timeout - Time to wait for a response (millis.) - * @throws IOException - Exception in I/O. - * @throws IllegalArgumentException - Illegal argument - * @throws InterruptedException - Interrupted during wait. - * @return true if AYT received a response, false otherwise - **/ - final boolean _sendAYT(long timeout) - throws IOException, IllegalArgumentException, InterruptedException - { - boolean retValue = false; - synchronized (aytMonitor) - { - synchronized (this) - { - aytFlag = false; - _output_.write(_COMMAND_AYT); - _output_.flush(); - } - - try - { - aytMonitor.wait(timeout); - if (aytFlag == false) - { - retValue = false; - aytFlag = true; - } - else - { - retValue = true; - } - } - catch (IllegalMonitorStateException e) - { - System.err.println("Exception processing AYT:" - + e.getMessage()); - } - } - - return (retValue); - } - /* Code Section added for supporting AYT (end)*/ - - /* open TelnetOptionHandler functionality (start)*/ - - /** - * Registers a new TelnetOptionHandler for this telnet to use. - * - * @param opthand - option handler to be registered. - * @throws InvalidTelnetOptionException - The option code is invalid. - **/ - void addOptionHandler(TelnetOptionHandler opthand) - throws InvalidTelnetOptionException - { - int optcode = opthand.getOptionCode(); - if (TelnetOption.isValidOption(optcode)) - { - if (optionHandlers[optcode] == null) - { - optionHandlers[optcode] = opthand; - if (isConnected()) - { - if (opthand.getInitLocal()) - { - try - { - _requestWill(optcode); - } - catch (IOException e) - { - System.err.println( - "Exception while initializing option: " - + e.getMessage()); - } - } - - if (opthand.getInitRemote()) - { - try - { - _requestDo(optcode); - } - catch (IOException e) - { - System.err.println( - "Exception while initializing option: " - + e.getMessage()); - } - } - } - } - else - { - throw (new InvalidTelnetOptionException( - "Already registered option", optcode)); - } - } - else - { - throw (new InvalidTelnetOptionException( - "Invalid Option Code", optcode)); - } - } - - /** - * Unregisters a TelnetOptionHandler. - * - * @param optcode - Code of the option to be unregistered. - * @throws InvalidTelnetOptionException - The option code is invalid. - **/ - void deleteOptionHandler(int optcode) - throws InvalidTelnetOptionException - { - if (TelnetOption.isValidOption(optcode)) - { - if (optionHandlers[optcode] == null) - { - throw (new InvalidTelnetOptionException( - "Unregistered option", optcode)); - } - else - { - TelnetOptionHandler opthand = optionHandlers[optcode]; - optionHandlers[optcode] = null; - - if (opthand.getWill()) - { - try - { - _requestWont(optcode); - } - catch (IOException e) - { - System.err.println( - "Exception while turning off option: " - + e.getMessage()); - } - } - - if (opthand.getDo()) - { - try - { - _requestDont(optcode); - } - catch (IOException e) - { - System.err.println( - "Exception while turning off option: " - + e.getMessage()); - } - } - } - } - else - { - throw (new InvalidTelnetOptionException( - "Invalid Option Code", optcode)); - } - } - /* open TelnetOptionHandler functionality (end)*/ - - /* Code Section added for supporting spystreams (start)*/ - /*** - * Registers an OutputStream for spying what's going on in - * the Telnet session. - *

- * @param spystream - OutputStream on which session activity - * will be echoed. - ***/ - void _registerSpyStream(OutputStream spystream) - { - spyStream = spystream; - } - - /*** - * Stops spying this Telnet. - *

- ***/ - void _stopSpyStream() - { - spyStream = null; - } - - /*** - * Sends a read char on the spy stream. - *

- * @param ch - character read from the session - ***/ - void _spyRead(int ch) - { - if (spyStream != null) - { - try - { - if (ch != '\r') - { - spyStream.write(ch); - if (ch == '\n') - { - spyStream.write('\r'); - } - spyStream.flush(); - } - } - catch (IOException e) - { - spyStream = null; - } - } - } - - /*** - * Sends a written char on the spy stream. - *

- * @param ch - character written to the session - ***/ - void _spyWrite(int ch) - { - if (!(_stateIsDo(TelnetOption.ECHO) - && _requestedDo(TelnetOption.ECHO))) - { - if (spyStream != null) - { - try - { - spyStream.write(ch); - spyStream.flush(); - } - catch (IOException e) - { - spyStream = null; - } - } - } - } - /* Code Section added for supporting spystreams (end)*/ - - /*** - * Registers a notification handler to which will be sent - * notifications of received telnet option negotiation commands. - *

- * @param notifhand - TelnetNotificationHandler to be registered - ***/ - public void registerNotifHandler(TelnetNotificationHandler notifhand) - { - __notifhand = notifhand; - } - - /*** - * Unregisters the current notification handler. - *

- ***/ - public void unregisterNotifHandler() - { - __notifhand = null; - } -} diff --git a/org/apache/commons/net/telnet/TelnetClient.java b/org/apache/commons/net/telnet/TelnetClient.java deleted file mode 100644 index 3237779..0000000 --- a/org/apache/commons/net/telnet/TelnetClient.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.apache.commons.net.io.FromNetASCIIInputStream; -import org.apache.commons.net.io.ToNetASCIIOutputStream; - -/*** - * The TelnetClient class implements the simple network virtual - * terminal (NVT) for the Telnet protocol according to RFC 854. It - * does not implement any of the extra Telnet options because it - * is meant to be used within a Java program providing automated - * access to Telnet accessible resources. - *

- * The class can be used by first connecting to a server using the - * SocketClient - * {@link org.apache.commons.net.SocketClient#connect connect} - * method. Then an InputStream and OutputStream for sending and - * receiving data over the Telnet connection can be obtained by - * using the {@link #getInputStream getInputStream() } and - * {@link #getOutputStream getOutputStream() } methods. - * When you finish using the streams, you must call - * {@link #disconnect disconnect } rather than simply - * closing the streams. - *

- *

- * @author Daniel F. Savarese - * @author Bruno D'Avanzo - ***/ - -public class TelnetClient extends Telnet -{ - private InputStream __input; - private OutputStream __output; - protected boolean readerThread = true; - - /*** - * Default TelnetClient constructor. - ***/ - public TelnetClient() - { - /* TERMINAL-TYPE option (start)*/ - super ("VT100"); - /* TERMINAL-TYPE option (end)*/ - __input = null; - __output = null; - } - - /* TERMINAL-TYPE option (start)*/ - public TelnetClient(String termtype) - { - super (termtype); - __input = null; - __output = null; - } - /* TERMINAL-TYPE option (end)*/ - - void _flushOutputStream() throws IOException - { - _output_.flush(); - } - void _closeOutputStream() throws IOException - { - _output_.close(); - } - - /*** - * Handles special connection requirements. - *

- * @exception IOException If an error occurs during connection setup. - ***/ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - InputStream input; - TelnetInputStream tmp; - - if (FromNetASCIIInputStream.isConversionRequired()) - input = new FromNetASCIIInputStream(_input_); - else - input = _input_; - - - tmp = new TelnetInputStream(input, this, readerThread); - if(readerThread) - { - tmp._start(); - } - // __input CANNOT refer to the TelnetInputStream. We run into - // blocking problems when some classes use TelnetInputStream, so - // we wrap it with a BufferedInputStream which we know is safe. - // This blocking behavior requires further investigation, but right - // now it looks like classes like InputStreamReader are not implemented - // in a safe manner. - __input = new BufferedInputStream(tmp); - __output = new ToNetASCIIOutputStream(new TelnetOutputStream(this)); - } - - /*** - * Disconnects the telnet session, closing the input and output streams - * as well as the socket. If you have references to the - * input and output streams of the telnet connection, you should not - * close them yourself, but rather call disconnect to properly close - * the connection. - ***/ - @Override - public void disconnect() throws IOException - { - if (__input != null) - __input.close(); - if (__output != null) - __output.close(); - super.disconnect(); - } - - /*** - * Returns the telnet connection output stream. You should not close the - * stream when you finish with it. Rather, you should call - * {@link #disconnect disconnect }. - *

- * @return The telnet connection output stream. - ***/ - public OutputStream getOutputStream() - { - return __output; - } - - /*** - * Returns the telnet connection input stream. You should not close the - * stream when you finish with it. Rather, you should call - * {@link #disconnect disconnect }. - *

- * @return The telnet connection input stream. - ***/ - public InputStream getInputStream() - { - return __input; - } - - /*** - * Returns the state of the option on the local side. - *

- * @param option - Option to be checked. - *

- * @return The state of the option on the local side. - ***/ - public boolean getLocalOptionState(int option) - { - /* BUG (option active when not already acknowledged) (start)*/ - return (_stateIsWill(option) && _requestedWill(option)); - /* BUG (option active when not already acknowledged) (end)*/ - } - - /*** - * Returns the state of the option on the remote side. - *

- * @param option - Option to be checked. - *

- * @return The state of the option on the remote side. - ***/ - public boolean getRemoteOptionState(int option) - { - /* BUG (option active when not already acknowledged) (start)*/ - return (_stateIsDo(option) && _requestedDo(option)); - /* BUG (option active when not already acknowledged) (end)*/ - } - /* open TelnetOptionHandler functionality (end)*/ - - /* Code Section added for supporting AYT (start)*/ - - /*** - * Sends an Are You There sequence and waits for the result. - *

- * @throws InterruptedException - * @throws IllegalArgumentException - * @throws IOException - *

- * @param timeout - Time to wait for a response (millis.) - *

- * @return true if AYT received a response, false otherwise - ***/ - public boolean sendAYT(long timeout) - throws IOException, IllegalArgumentException, InterruptedException - { - return (_sendAYT(timeout)); - } - /* Code Section added for supporting AYT (start)*/ - - /* open TelnetOptionHandler functionality (start)*/ - - /*** - * Registers a new TelnetOptionHandler for this telnet client to use. - *

- * @param opthand - option handler to be registered. - *

- * @throws InvalidTelnetOptionException - ***/ - @Override - public void addOptionHandler(TelnetOptionHandler opthand) - throws InvalidTelnetOptionException - { - super.addOptionHandler(opthand); - } - /* open TelnetOptionHandler functionality (end)*/ - - /*** - * Unregisters a TelnetOptionHandler. - *

- * @param optcode - Code of the option to be unregistered. - *

- * @throws InvalidTelnetOptionException - ***/ - @Override - public void deleteOptionHandler(int optcode) - throws InvalidTelnetOptionException - { - super.deleteOptionHandler(optcode); - } - - /* Code Section added for supporting spystreams (start)*/ - /*** - * Registers an OutputStream for spying what's going on in - * the TelnetClient session. - *

- * @param spystream - OutputStream on which session activity - * will be echoed. - ***/ - public void registerSpyStream(OutputStream spystream) - { - super._registerSpyStream(spystream); - } - - /*** - * Stops spying this TelnetClient. - *

- ***/ - public void stopSpyStream() - { - super._stopSpyStream(); - } - /* Code Section added for supporting spystreams (end)*/ - - /*** - * Registers a notification handler to which will be sent - * notifications of received telnet option negotiation commands. - *

- * @param notifhand - TelnetNotificationHandler to be registered - ***/ - @Override - public void registerNotifHandler(TelnetNotificationHandler notifhand) - { - super.registerNotifHandler(notifhand); - } - - /*** - * Unregisters the current notification handler. - *

- ***/ - @Override - public void unregisterNotifHandler() - { - super.unregisterNotifHandler(); - } - - /*** - * Sets the status of the reader thread. - * The reader thread status will apply to all subsequent connections - *

- * @param flag - true switches the reader thread on, false switches it off - ***/ - public void setReaderThread(boolean flag) - { - readerThread = flag; - } - - /*** - * Gets the status of the reader thread. - *

- * @return true if the reader thread is on, false otherwise - ***/ - public boolean getReaderThread() - { - return (readerThread); - } -} diff --git a/org/apache/commons/net/telnet/TelnetCommand.java b/org/apache/commons/net/telnet/TelnetCommand.java deleted file mode 100644 index 725057b..0000000 --- a/org/apache/commons/net/telnet/TelnetCommand.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/** - * The TelnetCommand class cannot be instantiated and only serves as a - * storehouse for telnet command constants. - * @author Daniel F. Savarese - * @see org.apache.commons.net.telnet.Telnet - * @see org.apache.commons.net.telnet.TelnetClient - */ - -public final class TelnetCommand -{ - /*** The maximum value a command code can have. This value is 255. ***/ - public static final int MAX_COMMAND_VALUE = 255; - - /*** Interpret As Command code. Value is 255 according to RFC 854. ***/ - public static final int IAC = 255; - - /*** Don't use option code. Value is 254 according to RFC 854. ***/ - public static final int DONT = 254; - - /*** Request to use option code. Value is 253 according to RFC 854. ***/ - public static final int DO = 253; - - /*** Refuse to use option code. Value is 252 according to RFC 854. ***/ - public static final int WONT = 252; - - /*** Agree to use option code. Value is 251 according to RFC 854. ***/ - public static final int WILL = 251; - - /*** Start subnegotiation code. Value is 250 according to RFC 854. ***/ - public static final int SB = 250; - - /*** Go Ahead code. Value is 249 according to RFC 854. ***/ - public static final int GA = 249; - - /*** Erase Line code. Value is 248 according to RFC 854. ***/ - public static final int EL = 248; - - /*** Erase Character code. Value is 247 according to RFC 854. ***/ - public static final int EC = 247; - - /*** Are You There code. Value is 246 according to RFC 854. ***/ - public static final int AYT = 246; - - /*** Abort Output code. Value is 245 according to RFC 854. ***/ - public static final int AO = 245; - - /*** Interrupt Process code. Value is 244 according to RFC 854. ***/ - public static final int IP = 244; - - /*** Break code. Value is 243 according to RFC 854. ***/ - public static final int BREAK = 243; - - /*** Data mark code. Value is 242 according to RFC 854. ***/ - public static final int DM = 242; - - /*** No Operation code. Value is 241 according to RFC 854. ***/ - public static final int NOP = 241; - - /*** End subnegotiation code. Value is 240 according to RFC 854. ***/ - public static final int SE = 240; - - /*** End of record code. Value is 239. ***/ - public static final int EOR = 239; - - /*** Abort code. Value is 238. ***/ - public static final int ABORT = 238; - - /*** Suspend process code. Value is 237. ***/ - public static final int SUSP = 237; - - /*** End of file code. Value is 236. ***/ - public static final int EOF = 236; - - /*** Synchronize code. Value is 242. ***/ - public static final int SYNCH = 242; - - /*** String representations of commands. ***/ - private static final String __commandString[] = { - "IAC", "DONT", "DO", "WONT", "WILL", "SB", "GA", "EL", "EC", "AYT", - "AO", "IP", "BRK", "DMARK", "NOP", "SE", "EOR", "ABORT", "SUSP", "EOF" - }; - - private static final int __FIRST_COMMAND = IAC; - private static final int __LAST_COMMAND = EOF; - - /*** - * Returns the string representation of the telnet protocol command - * corresponding to the given command code. - *

- * @param code The command code of the telnet protocol command. - * @return The string representation of the telnet protocol command. - ***/ - public static final String getCommand(int code) - { - return __commandString[__FIRST_COMMAND - code]; - } - - /*** - * Determines if a given command code is valid. Returns true if valid, - * false if not. - *

- * @param code The command code to test. - * @return True if the command code is valid, false if not. - **/ - public static final boolean isValidCommand(int code) - { - return (code <= __FIRST_COMMAND && code >= __LAST_COMMAND); - } - - // Cannot be instantiated - private TelnetCommand() - { } -} diff --git a/org/apache/commons/net/telnet/TelnetInputStream.java b/org/apache/commons/net/telnet/TelnetInputStream.java deleted file mode 100644 index 8a83b68..0000000 --- a/org/apache/commons/net/telnet/TelnetInputStream.java +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; - -/*** - * - *

- * - *

- *

- * @author Daniel F. Savarese - * @author Bruno D'Avanzo - ***/ - - -final class TelnetInputStream extends BufferedInputStream implements Runnable -{ - static final int _STATE_DATA = 0, _STATE_IAC = 1, _STATE_WILL = 2, - _STATE_WONT = 3, _STATE_DO = 4, _STATE_DONT = 5, - _STATE_SB = 6, _STATE_SE = 7, _STATE_CR = 8, _STATE_IAC_SB = 9; - - private boolean __hasReachedEOF, __isClosed; - private boolean __readIsWaiting; - private int __receiveState, __queueHead, __queueTail, __bytesAvailable; - private int[] __queue; - private TelnetClient __client; - private Thread __thread; - private IOException __ioException; - - /* TERMINAL-TYPE option (start)*/ - private int __suboption[] = new int[256]; - private int __suboption_count = 0; - /* TERMINAL-TYPE option (end)*/ - - private boolean __threaded; - - TelnetInputStream(InputStream input, TelnetClient client, - boolean readerThread) - { - super(input); - __client = client; - __receiveState = _STATE_DATA; - __isClosed = true; - __hasReachedEOF = false; - // Make it 2049, because when full, one slot will go unused, and we - // want a 2048 byte buffer just to have a round number (base 2 that is) - __queue = new int[2049]; - __queueHead = 0; - __queueTail = 0; - __bytesAvailable = 0; - __ioException = null; - __readIsWaiting = false; - __threaded = false; - if(readerThread) - __thread = new Thread(this); - else - __thread = null; - } - - TelnetInputStream(InputStream input, TelnetClient client) { - this(input, client, true); - } - - void _start() - { - if(__thread == null) - return; - - int priority; - __isClosed = false; - // TODO remove this - // Need to set a higher priority in case JVM does not use pre-emptive - // threads. This should prevent scheduler induced deadlock (rather than - // deadlock caused by a bug in this code). - priority = Thread.currentThread().getPriority() + 1; - if (priority > Thread.MAX_PRIORITY) - priority = Thread.MAX_PRIORITY; - __thread.setPriority(priority); - __thread.setDaemon(true); - __thread.start(); - __threaded = true; - } - - - // synchronized(__client) critical sections are to protect against - // TelnetOutputStream writing through the telnet client at same time - // as a processDo/Will/etc. command invoked from TelnetInputStream - // tries to write. - private int __read(boolean mayBlock) throws IOException - { - int ch; - -_loop: - while (true) - { - - // If there is no more data AND we were told not to block, just return -2. (More efficient than exception.) - if(!mayBlock && super.available() == 0) - return -2; - - // Otherwise, exit only when we reach end of stream. - if ((ch = super.read()) < 0) - return -1; - - ch = (ch & 0xff); - - /* Code Section added for supporting AYT (start)*/ - synchronized (__client) - { - __client._processAYTResponse(); - } - /* Code Section added for supporting AYT (end)*/ - - /* Code Section added for supporting spystreams (start)*/ - __client._spyRead(ch); - /* Code Section added for supporting spystreams (end)*/ - -_mainSwitch: - switch (__receiveState) - { - - case _STATE_CR: - if (ch == '\0') - { - // Strip null - continue; - } - // How do we handle newline after cr? - // else if (ch == '\n' && _requestedDont(TelnetOption.ECHO) && - - // Handle as normal data by falling through to _STATE_DATA case - - case _STATE_DATA: - if (ch == TelnetCommand.IAC) - { - __receiveState = _STATE_IAC; - continue; - } - - - if (ch == '\r') - { - synchronized (__client) - { - if (__client._requestedDont(TelnetOption.BINARY)) - __receiveState = _STATE_CR; - else - __receiveState = _STATE_DATA; - } - } - else - __receiveState = _STATE_DATA; - break; - - case _STATE_IAC: - switch (ch) - { - case TelnetCommand.WILL: - __receiveState = _STATE_WILL; - continue; - case TelnetCommand.WONT: - __receiveState = _STATE_WONT; - continue; - case TelnetCommand.DO: - __receiveState = _STATE_DO; - continue; - case TelnetCommand.DONT: - __receiveState = _STATE_DONT; - continue; - /* TERMINAL-TYPE option (start)*/ - case TelnetCommand.SB: - __suboption_count = 0; - __receiveState = _STATE_SB; - continue; - /* TERMINAL-TYPE option (end)*/ - case TelnetCommand.IAC: - __receiveState = _STATE_DATA; - break; - default: - break; - } - __receiveState = _STATE_DATA; - continue; - case _STATE_WILL: - synchronized (__client) - { - __client._processWill(ch); - __client._flushOutputStream(); - } - __receiveState = _STATE_DATA; - continue; - case _STATE_WONT: - synchronized (__client) - { - __client._processWont(ch); - __client._flushOutputStream(); - } - __receiveState = _STATE_DATA; - continue; - case _STATE_DO: - synchronized (__client) - { - __client._processDo(ch); - __client._flushOutputStream(); - } - __receiveState = _STATE_DATA; - continue; - case _STATE_DONT: - synchronized (__client) - { - __client._processDont(ch); - __client._flushOutputStream(); - } - __receiveState = _STATE_DATA; - continue; - /* TERMINAL-TYPE option (start)*/ - case _STATE_SB: - switch (ch) - { - case TelnetCommand.IAC: - __receiveState = _STATE_IAC_SB; - continue; - default: - // store suboption char - __suboption[__suboption_count++] = ch; - break; - } - __receiveState = _STATE_SB; - continue; - case _STATE_IAC_SB: - switch (ch) - { - case TelnetCommand.SE: - synchronized (__client) - { - __client._processSuboption(__suboption, __suboption_count); - __client._flushOutputStream(); - } - __receiveState = _STATE_DATA; - continue; - default: - __receiveState = _STATE_SB; - break; - } - __receiveState = _STATE_DATA; - continue; - /* TERMINAL-TYPE option (end)*/ - } - - break; - } - - return ch; - } - - // synchronized(__client) critical sections are to protect against - // TelnetOutputStream writing through the telnet client at same time - // as a processDo/Will/etc. command invoked from TelnetInputStream - // tries to write. - private void __processChar(int ch) throws InterruptedException - { - // Critical section because we're altering __bytesAvailable, - // __queueTail, and the contents of _queue. - synchronized (__queue) - { - while (__bytesAvailable >= __queue.length - 1) - { - // The queue is full. We need to wait before adding any more data to it. Hopefully the stream owner - // will consume some data soon! - if(__threaded) - { - __queue.notify(); - try - { - __queue.wait(); - } - catch (InterruptedException e) - { - throw e; - } - } - else - { - // We've been asked to add another character to the queue, but it is already full and there's - // no other thread to drain it. This should not have happened! - throw new IllegalStateException("Queue is full! Cannot process another character."); - } - } - - // Need to do this in case we're not full, but block on a read - if (__readIsWaiting && __threaded) - { - __queue.notify(); - } - - __queue[__queueTail] = ch; - ++__bytesAvailable; - - if (++__queueTail >= __queue.length) - __queueTail = 0; - } - } - - @Override - public int read() throws IOException - { - // Critical section because we're altering __bytesAvailable, - // __queueHead, and the contents of _queue in addition to - // testing value of __hasReachedEOF. - synchronized (__queue) - { - - while (true) - { - if (__ioException != null) - { - IOException e; - e = __ioException; - __ioException = null; - throw e; - } - - if (__bytesAvailable == 0) - { - // Return -1 if at end of file - if (__hasReachedEOF) - return -1; - - // Otherwise, we have to wait for queue to get something - if(__threaded) - { - __queue.notify(); - try - { - __readIsWaiting = true; - __queue.wait(); - __readIsWaiting = false; - } - catch (InterruptedException e) - { - throw new InterruptedIOException("Fatal thread interruption during read."); - } - } - else - { - //__alreadyread = false; - __readIsWaiting = true; - int ch; - boolean mayBlock = true; // block on the first read only - - do - { - try - { - if ((ch = __read(mayBlock)) < 0) - if(ch != -2) - return (ch); - } - catch (InterruptedIOException e) - { - synchronized (__queue) - { - __ioException = e; - __queue.notifyAll(); - try - { - __queue.wait(100); - } - catch (InterruptedException interrupted) - { - } - } - return (-1); - } - - - try - { - if(ch != -2) - { - __processChar(ch); - } - } - catch (InterruptedException e) - { - if (__isClosed) - return (-1); - } - - // Reads should not block on subsequent iterations. Potentially, this could happen if the - // remaining buffered socket data consists entirely of Telnet command sequence and no "user" data. - mayBlock = false; - - } - // Continue reading as long as there is data available and the queue is not full. - while (super.available() > 0 && __bytesAvailable < __queue.length - 1); - - __readIsWaiting = false; - } - continue; - } - else - { - int ch; - - ch = __queue[__queueHead]; - - if (++__queueHead >= __queue.length) - __queueHead = 0; - - --__bytesAvailable; - - // Need to explicitly notify() so available() works properly - if(__bytesAvailable == 0 && __threaded) { - __queue.notify(); - } - - return ch; - } - } - } - } - - - /*** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - *

- * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @exception IOException If an error occurs in reading the underlying - * stream. - ***/ - @Override - public int read(byte buffer[]) throws IOException - { - return read(buffer, 0, buffer.length); - } - - - /*** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - *

- * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @exception IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override - public int read(byte buffer[], int offset, int length) throws IOException - { - int ch, off; - - if (length < 1) - return 0; - - // Critical section because run() may change __bytesAvailable - synchronized (__queue) - { - if (length > __bytesAvailable) - length = __bytesAvailable; - } - - if ((ch = read()) == -1) - return -1; - - off = offset; - - do - { - buffer[offset++] = (byte)ch; - } - while (--length > 0 && (ch = read()) != -1); - - //__client._spyRead(buffer, off, offset - off); - return (offset - off); - } - - - /*** Returns false. Mark is not supported. ***/ - @Override - public boolean markSupported() - { - return false; - } - - @Override - public int available() throws IOException - { - // Critical section because run() may change __bytesAvailable - synchronized (__queue) - { - return __bytesAvailable; - } - } - - - // Cannot be synchronized. Will cause deadlock if run() is blocked - // in read because BufferedInputStream read() is synchronized. - @Override - public void close() throws IOException - { - // Completely disregard the fact thread may still be running. - // We can't afford to block on this close by waiting for - // thread to terminate because few if any JVM's will actually - // interrupt a system read() from the interrupt() method. - super.close(); - - synchronized (__queue) - { - __hasReachedEOF = true; - __isClosed = true; - - if (__thread != null && __thread.isAlive()) - { - __thread.interrupt(); - } - - __queue.notifyAll(); - } - - __threaded = false; - } - - public void run() - { - int ch; - - try - { -_outerLoop: - while (!__isClosed) - { - try - { - if ((ch = __read(true)) < 0) - break; - } - catch (InterruptedIOException e) - { - synchronized (__queue) - { - __ioException = e; - __queue.notifyAll(); - try - { - __queue.wait(100); - } - catch (InterruptedException interrupted) - { - if (__isClosed) - break _outerLoop; - } - continue; - } - } catch(RuntimeException re) { - // We treat any runtime exceptions as though the - // stream has been closed. We close the - // underlying stream just to be sure. - super.close(); - // Breaking the loop has the effect of setting - // the state to closed at the end of the method. - break _outerLoop; - } - - try - { - __processChar(ch); - } - catch (InterruptedException e) - { - if (__isClosed) - break _outerLoop; - } - } - } - catch (IOException ioe) - { - synchronized (__queue) - { - __ioException = ioe; - } - } - - synchronized (__queue) - { - __isClosed = true; // Possibly redundant - __hasReachedEOF = true; - __queue.notify(); - } - - __threaded = false; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/org/apache/commons/net/telnet/TelnetNotificationHandler.java b/org/apache/commons/net/telnet/TelnetNotificationHandler.java deleted file mode 100644 index d509021..0000000 --- a/org/apache/commons/net/telnet/TelnetNotificationHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * The TelnetNotificationHandler interface can be used to handle - * notification of options negotiation commands received on a telnet - * session. - *

- * The user can implement this interface and register a - * TelnetNotificationHandler by using the registerNotificationHandler() - * of TelnetClient to be notified of option negotiation commands. - *

- *

- * @author Bruno D'Avanzo - ***/ - -public interface TelnetNotificationHandler -{ - /*** - * The remote party sent a DO command. - ***/ - public static final int RECEIVED_DO = 1; - - /*** - * The remote party sent a DONT command. - ***/ - public static final int RECEIVED_DONT = 2; - - /*** - * The remote party sent a WILL command. - ***/ - public static final int RECEIVED_WILL = 3; - - /*** - * The remote party sent a WONT command. - ***/ - public static final int RECEIVED_WONT = 4; - - /*** - * Callback method called when TelnetClient receives an option - * negotiation command. - *

- * @param negotiation_code - type of negotiation command received - * (RECEIVED_DO, RECEIVED_DONT, RECEIVED_WILL, RECEIVED_WONT) - *

- * @param option_code - code of the option negotiated - *

- ***/ - public void receivedNegotiation(int negotiation_code, int option_code); -} diff --git a/org/apache/commons/net/telnet/TelnetOption.java b/org/apache/commons/net/telnet/TelnetOption.java deleted file mode 100644 index 77799b6..0000000 --- a/org/apache/commons/net/telnet/TelnetOption.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * The TelnetOption class cannot be instantiated and only serves as a - * storehouse for telnet option constants. - *

- * Details regarding Telnet option specification can be found in RFC 855. - *

- *

- * @author Daniel F. Savarese - * @see org.apache.commons.net.telnet.Telnet - * @see org.apache.commons.net.telnet.TelnetClient - ***/ - -public class TelnetOption -{ - /*** The maximum value an option code can have. This value is 255. ***/ - public static final int MAX_OPTION_VALUE = 255; - - public static final int BINARY = 0; - - public static final int ECHO = 1; - - public static final int PREPARE_TO_RECONNECT = 2; - - public static final int SUPPRESS_GO_AHEAD = 3; - - public static final int APPROXIMATE_MESSAGE_SIZE = 4; - - public static final int STATUS = 5; - - public static final int TIMING_MARK = 6; - - public static final int REMOTE_CONTROLLED_TRANSMISSION = 7; - - public static final int NEGOTIATE_OUTPUT_LINE_WIDTH = 8; - - public static final int NEGOTIATE_OUTPUT_PAGE_SIZE = 9; - - public static final int NEGOTIATE_CARRIAGE_RETURN = 10; - - public static final int NEGOTIATE_HORIZONTAL_TAB_STOP = 11; - - public static final int NEGOTIATE_HORIZONTAL_TAB = 12; - - public static final int NEGOTIATE_FORMFEED = 13; - - public static final int NEGOTIATE_VERTICAL_TAB_STOP = 14; - - public static final int NEGOTIATE_VERTICAL_TAB = 15; - - public static final int NEGOTIATE_LINEFEED = 16; - - public static final int EXTENDED_ASCII = 17; - - public static final int FORCE_LOGOUT = 18; - - public static final int BYTE_MACRO = 19; - - public static final int DATA_ENTRY_TERMINAL = 20; - - public static final int SUPDUP = 21; - - public static final int SUPDUP_OUTPUT = 22; - - public static final int SEND_LOCATION = 23; - - public static final int TERMINAL_TYPE = 24; - - public static final int END_OF_RECORD = 25; - - public static final int TACACS_USER_IDENTIFICATION = 26; - - public static final int OUTPUT_MARKING = 27; - - public static final int TERMINAL_LOCATION_NUMBER = 28; - - public static final int REGIME_3270 = 29; - - public static final int X3_PAD = 30; - - public static final int WINDOW_SIZE = 31; - - public static final int TERMINAL_SPEED = 32; - - public static final int REMOTE_FLOW_CONTROL = 33; - - public static final int LINEMODE = 34; - - public static final int X_DISPLAY_LOCATION = 35; - - public static final int OLD_ENVIRONMENT_VARIABLES = 36; - - public static final int AUTHENTICATION = 37; - - public static final int ENCRYPTION = 38; - - public static final int NEW_ENVIRONMENT_VARIABLES = 39; - - public static final int EXTENDED_OPTIONS_LIST = 255; - - private static final int __FIRST_OPTION = BINARY; - private static final int __LAST_OPTION = EXTENDED_OPTIONS_LIST; - - private static final String __optionString[] = { - "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS", - "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", - "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", - "BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", - "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", "TACACS UID", - "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", - "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", - "ENCRYPT", "NEW-ENVIRON", "TN3270E", "XAUTH", "CHARSET", "RSP", - "Com Port Control", "Suppress Local Echo", "Start TLS", - "KERMIT", "SEND-URL", "FORWARD_X", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "TELOPT PRAGMA LOGON", "TELOPT SSPI LOGON", - "TELOPT PRAGMA HEARTBEAT", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", "", "", - "Extended-Options-List" - }; - - - /*** - * Returns the string representation of the telnet protocol option - * corresponding to the given option code. - *

- * @param code The option code of the telnet protocol option - * @return The string representation of the telnet protocol option. - ***/ - public static final String getOption(int code) - { - if(__optionString[code].length() == 0) - { - return "UNASSIGNED"; - } - else - { - return __optionString[code]; - } - } - - - /*** - * Determines if a given option code is valid. Returns true if valid, - * false if not. - *

- * @param code The option code to test. - * @return True if the option code is valid, false if not. - **/ - public static final boolean isValidOption(int code) - { - return (code <= __LAST_OPTION); - } - - // Cannot be instantiated - private TelnetOption() - { } -} diff --git a/org/apache/commons/net/telnet/TelnetOptionHandler.java b/org/apache/commons/net/telnet/TelnetOptionHandler.java deleted file mode 100644 index 52486ba..0000000 --- a/org/apache/commons/net/telnet/TelnetOptionHandler.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * The TelnetOptionHandler class is the base class to be used - * for implementing handlers for telnet options. - *

- * TelnetOptionHandler implements basic option handling - * functionality and defines abstract methods that must be - * implemented to define subnegotiation behaviour. - *

- * @author Bruno D'Avanzo - ***/ -public abstract class TelnetOptionHandler -{ - /*** - * Option code - ***/ - private int optionCode = -1; - - /*** - * true if the option should be activated on the local side - ***/ - private boolean initialLocal = false; - - /*** - * true if the option should be activated on the remote side - ***/ - private boolean initialRemote = false; - - /*** - * true if the option should be accepted on the local side - ***/ - private boolean acceptLocal = false; - - /*** - * true if the option should be accepted on the remote side - ***/ - private boolean acceptRemote = false; - - /*** - * true if the option is active on the local side - ***/ - private boolean doFlag = false; - - /*** - * true if the option is active on the remote side - ***/ - private boolean willFlag = false; - - /*** - * Constructor for the TelnetOptionHandler. Allows defining desired - * initial setting for local/remote activation of this option and - * behaviour in case a local/remote activation request for this - * option is received. - *

- * @param optcode - Option code. - * @param initlocal - if set to true, a WILL is sent upon connection. - * @param initremote - if set to true, a DO is sent upon connection. - * @param acceptlocal - if set to true, any DO request is accepted. - * @param acceptremote - if set to true, any WILL request is accepted. - ***/ - public TelnetOptionHandler(int optcode, - boolean initlocal, - boolean initremote, - boolean acceptlocal, - boolean acceptremote) - { - optionCode = optcode; - initialLocal = initlocal; - initialRemote = initremote; - acceptLocal = acceptlocal; - acceptRemote = acceptremote; - } - - - /*** - * Returns the option code for this option. - *

- * @return Option code. - ***/ - public int getOptionCode() - { - return (optionCode); - } - - /*** - * Returns a boolean indicating whether to accept a DO - * request coming from the other end. - *

- * @return true if a DO request shall be accepted. - ***/ - public boolean getAcceptLocal() - { - return (acceptLocal); - } - - /*** - * Returns a boolean indicating whether to accept a WILL - * request coming from the other end. - *

- * @return true if a WILL request shall be accepted. - ***/ - public boolean getAcceptRemote() - { - return (acceptRemote); - } - - /*** - * Set behaviour of the option for DO requests coming from - * the other end. - *

- * @param accept - if true, subsequent DO requests will be accepted. - ***/ - public void setAcceptLocal(boolean accept) - { - acceptLocal = accept; - } - - /*** - * Set behaviour of the option for WILL requests coming from - * the other end. - *

- * @param accept - if true, subsequent WILL requests will be accepted. - ***/ - public void setAcceptRemote(boolean accept) - { - acceptRemote = accept; - } - - /*** - * Returns a boolean indicating whether to send a WILL request - * to the other end upon connection. - *

- * @return true if a WILL request shall be sent upon connection. - ***/ - public boolean getInitLocal() - { - return (initialLocal); - } - - /*** - * Returns a boolean indicating whether to send a DO request - * to the other end upon connection. - *

- * @return true if a DO request shall be sent upon connection. - ***/ - public boolean getInitRemote() - { - return (initialRemote); - } - - /*** - * Tells this option whether to send a WILL request upon connection. - *

- * @param init - if true, a WILL request will be sent upon subsequent - * connections. - ***/ - public void setInitLocal(boolean init) - { - initialLocal = init; - } - - /*** - * Tells this option whether to send a DO request upon connection. - *

- * @param init - if true, a DO request will be sent upon subsequent - * connections. - ***/ - public void setInitRemote(boolean init) - { - initialRemote = init; - } - - /*** - * Method called upon reception of a subnegotiation for this option - * coming from the other end. - * Must be implemented by the actual TelnetOptionHandler to specify - * which response must be sent for the subnegotiation request. - *

- * @param suboptionData - the sequence received, whithout IAC SB & IAC SE - * @param suboptionLength - the length of data in suboption_data - *

- * @return response to be sent to the subnegotiation sequence. TelnetClient - * will add IAC SB & IAC SE. null means no response - ***/ - public abstract int[] answerSubnegotiation(int suboptionData[], - int suboptionLength); - - /*** - * This method is invoked whenever this option is acknowledged active on - * the local end (TelnetClient sent a WILL, remote side sent a DO). - * The method is used to specify a subnegotiation sequence that will be - * sent by TelnetClient when the option is activated. - *

- * @return subnegotiation sequence to be sent by TelnetClient. TelnetClient - * will add IAC SB & IAC SE. null means no subnegotiation. - ***/ - public abstract int[] startSubnegotiationLocal(); - - /*** - * This method is invoked whenever this option is acknowledged active on - * the remote end (TelnetClient sent a DO, remote side sent a WILL). - * The method is used to specify a subnegotiation sequence that will be - * sent by TelnetClient when the option is activated. - *

- * @return subnegotiation sequence to be sent by TelnetClient. TelnetClient - * will add IAC SB & IAC SE. null means no subnegotiation. - ***/ - public abstract int[] startSubnegotiationRemote(); - - /*** - * Returns a boolean indicating whether a WILL request sent to the other - * side has been acknowledged. - *

- * @return true if a WILL sent to the other side has been acknowledged. - ***/ - boolean getWill() - { - return willFlag; - } - - /*** - * Tells this option whether a WILL request sent to the other - * side has been acknowledged (invoked by TelnetClient). - *

- * @param state - if true, a WILL request has been acknowledged. - ***/ - void setWill(boolean state) - { - willFlag = state; - } - - /*** - * Returns a boolean indicating whether a DO request sent to the other - * side has been acknowledged. - *

- * @return true if a DO sent to the other side has been acknowledged. - ***/ - boolean getDo() - { - return doFlag; - } - - - /*** - * Tells this option whether a DO request sent to the other - * side has been acknowledged (invoked by TelnetClient). - *

- * @param state - if true, a DO request has been acknowledged. - ***/ - void setDo(boolean state) - { - doFlag = state; - } -} diff --git a/org/apache/commons/net/telnet/TelnetOutputStream.java b/org/apache/commons/net/telnet/TelnetOutputStream.java deleted file mode 100644 index fd796d1..0000000 --- a/org/apache/commons/net/telnet/TelnetOutputStream.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -import java.io.IOException; -import java.io.OutputStream; - -/*** - * - *

- * - *

- *

- * @author Daniel F. Savarese - ***/ - - -final class TelnetOutputStream extends OutputStream -{ - private TelnetClient __client; - private boolean __convertCRtoCRLF = true; - private boolean __lastWasCR = false; - - TelnetOutputStream(TelnetClient client) - { - __client = client; - } - - - /*** - * Writes a byte to the stream. - *

- * @param ch The byte to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public void write(int ch) throws IOException - { - - synchronized (__client) - { - ch &= 0xff; - - if (__client._requestedWont(TelnetOption.BINARY)) - { - if (__lastWasCR) - { - if (__convertCRtoCRLF) - { - __client._sendByte('\n'); - if (ch == '\n') - { - __lastWasCR = false; - return ; - } - } - else if (ch != '\n') - __client._sendByte('\0'); - } - - __lastWasCR = false; - - switch (ch) - { - case '\r': - __client._sendByte('\r'); - __lastWasCR = true; - break; - case TelnetCommand.IAC: - __client._sendByte(TelnetCommand.IAC); - __client._sendByte(TelnetCommand.IAC); - break; - default: - __client._sendByte(ch); - break; - } - } - else if (ch == TelnetCommand.IAC) - { - __client._sendByte(ch); - __client._sendByte(TelnetCommand.IAC); - } - else - __client._sendByte(ch); - } - } - - - /*** - * Writes a byte array to the stream. - *

- * @param buffer The byte array to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public void write(byte buffer[]) throws IOException - { - write(buffer, 0, buffer.length); - } - - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - *

- * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @exception IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override - public void write(byte buffer[], int offset, int length) throws IOException - { - synchronized (__client) - { - while (length-- > 0) - write(buffer[offset++]); - } - } - - /*** Flushes the stream. ***/ - @Override - public void flush() throws IOException - { - __client._flushOutputStream(); - } - - /*** Closes the stream. ***/ - @Override - public void close() throws IOException - { - __client._closeOutputStream(); - } -} diff --git a/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java b/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java deleted file mode 100644 index 0cbe0c0..0000000 --- a/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * Implements the telnet terminal type option RFC 1091. - *

- * @author Bruno D'Avanzo - ***/ -public class TerminalTypeOptionHandler extends TelnetOptionHandler -{ - /*** - * Terminal type - ***/ - private String termType = null; - - /*** - * Terminal type option - ***/ - protected static final int TERMINAL_TYPE = 24; - - /*** - * Send (for subnegotiation) - ***/ - protected static final int TERMINAL_TYPE_SEND = 1; - - /*** - * Is (for subnegotiation) - ***/ - protected static final int TERMINAL_TYPE_IS = 0; - - /*** - * Constructor for the TerminalTypeOptionHandler. Allows defining desired - * initial setting for local/remote activation of this option and - * behaviour in case a local/remote activation request for this - * option is received. - *

- * @param termtype - terminal type that will be negotiated. - * @param initlocal - if set to true, a WILL is sent upon connection. - * @param initremote - if set to true, a DO is sent upon connection. - * @param acceptlocal - if set to true, any DO request is accepted. - * @param acceptremote - if set to true, any WILL request is accepted. - ***/ - public TerminalTypeOptionHandler(String termtype, - boolean initlocal, - boolean initremote, - boolean acceptlocal, - boolean acceptremote) - { - super(TelnetOption.TERMINAL_TYPE, initlocal, initremote, - acceptlocal, acceptremote); - termType = termtype; - } - - /*** - * Constructor for the TerminalTypeOptionHandler. Initial and accept - * behaviour flags are set to false - *

- * @param termtype - terminal type that will be negotiated. - ***/ - public TerminalTypeOptionHandler(String termtype) - { - super(TelnetOption.TERMINAL_TYPE, false, false, false, false); - termType = termtype; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @param suboptionData - the sequence received, whithout IAC SB & IAC SE - * @param suboptionLength - the length of data in suboption_data - *

- * @return terminal type information - ***/ - @Override - public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) - { - if ((suboptionData != null) && (suboptionLength > 1) - && (termType != null)) - { - if ((suboptionData[0] == TERMINAL_TYPE) - && (suboptionData[1] == TERMINAL_TYPE_SEND)) - { - int response[] = new int[termType.length() + 2]; - - response[0] = TERMINAL_TYPE; - response[1] = TERMINAL_TYPE_IS; - - for (int ii = 0; ii < termType.length(); ii++) - { - response[ii + 2] = termType.charAt(ii); - } - - return response; - } - } - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationLocal() - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationRemote() - { - return null; - } -} diff --git a/org/apache/commons/net/telnet/WindowSizeOptionHandler.java b/org/apache/commons/net/telnet/WindowSizeOptionHandler.java deleted file mode 100644 index 34bb46f..0000000 --- a/org/apache/commons/net/telnet/WindowSizeOptionHandler.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.telnet; - -/*** - * Implements the telnet window size option RFC 1073. - *

- * @author Yuval Kashtan - * @version $Id: WindowSizeOptionHandler.java 658520 2008-05-21 01:14:11Z sebb $ - * @since 2.0 - ***/ -public class WindowSizeOptionHandler extends TelnetOptionHandler -{ - /*** - * Horizontal Size - ***/ - private int m_nWidth = 80; - - /*** - * Vertical Size - ***/ - private int m_nHeight = 24; - - /*** - * Window size option - ***/ - protected static final int WINDOW_SIZE = 31; - - /*** - * Constructor for the WindowSizeOptionHandler. Allows defining desired - * initial setting for local/remote activation of this option and - * behaviour in case a local/remote activation request for this - * option is received. - *

- * @param nWidth - Window width. - * @param nHeight - Window Height - * @param initlocal - if set to true, a WILL is sent upon connection. - * @param initremote - if set to true, a DO is sent upon connection. - * @param acceptlocal - if set to true, any DO request is accepted. - * @param acceptremote - if set to true, any WILL request is accepted. - ***/ - public WindowSizeOptionHandler( - int nWidth, - int nHeight, - boolean initlocal, - boolean initremote, - boolean acceptlocal, - boolean acceptremote - ) { - super ( - TelnetOption.WINDOW_SIZE, - initlocal, - initremote, - acceptlocal, - acceptremote - ); - - m_nWidth = nWidth; - m_nHeight = nHeight; - } - - /*** - * Constructor for the WindowSizeOptionHandler. Initial and accept - * behaviour flags are set to false - *

- * @param nWidth - Window width. - * @param nHeight - Window Height - ***/ - public WindowSizeOptionHandler( - int nWidth, - int nHeight - ) { - super ( - TelnetOption.WINDOW_SIZE, - false, - false, - false, - false - ); - - m_nWidth = nWidth; - m_nHeight = nHeight; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @param suboptionData - the sequence received, whithout IAC SB & IAC SE - * @param suboptionLength - the length of data in suboption_data - *

- * @return terminal type information - ***/ - @Override - public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) - { - return null; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - * This will send the client Height and Width to the server. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationLocal() - { - int nCompoundWindowSize = m_nWidth * 0x10000 + m_nHeight; - int nResponseSize = 5; - int nIndex; - int nShift; - int nTurnedOnBits; - - if ((m_nWidth % 0x100) == 0xFF) { - nResponseSize += 1; - } - - if ((m_nWidth / 0x100) == 0xFF) { - nResponseSize += 1; - } - - if ((m_nHeight % 0x100) == 0xFF) { - nResponseSize += 1; - } - - if ((m_nHeight / 0x100) == 0xFF) { - nResponseSize += 1; - } - - // - // allocate response array - // - int response[] = new int[nResponseSize]; - - // - // Build response array. - // --------------------- - // 1. put option name. - // 2. loop through Window size and fill the values, - // 3. duplicate 'ff' if needed. - // - - response[0] = WINDOW_SIZE; // 1 // - - for ( // 2 // - nIndex=1, nShift = 24; - nIndex < nResponseSize; - nIndex++, nShift -=8 - ) { - nTurnedOnBits = 0xFF; - nTurnedOnBits <<= nShift; - response[nIndex] = (nCompoundWindowSize & nTurnedOnBits) >>> nShift; - - if (response[nIndex] == 0xff) { // 3 // - nIndex++; - response[nIndex] = 0xff; - } - } - - return response; - } - - /*** - * Implements the abstract method of TelnetOptionHandler. - *

- * @return always null (no response to subnegotiation) - ***/ - @Override - public int[] startSubnegotiationRemote() - { - return null; - } -} diff --git a/org/apache/commons/net/tftp/TFTP.java b/org/apache/commons/net/tftp/TFTP.java deleted file mode 100644 index 662da11..0000000 --- a/org/apache/commons/net/tftp/TFTP.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.DatagramPacket; -import java.net.SocketException; - -import org.apache.commons.net.DatagramSocketClient; - -/*** - * The TFTP class exposes a set of methods to allow you to deal with the TFTP - * protocol directly, in case you want to write your own TFTP client or - * server. However, almost every user should only be concerend with - * the {@link org.apache.commons.net.DatagramSocketClient#open open() }, - * and {@link org.apache.commons.net.DatagramSocketClient#close close() }, - * methods. Additionally,the a - * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() } - * method may be of importance for performance tuning. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. - *

- *

- * @author Daniel F. Savarese - * @see org.apache.commons.net.DatagramSocketClient - * @see TFTPPacket - * @see TFTPPacketException - * @see TFTPClient - ***/ - -public class TFTP extends DatagramSocketClient -{ - /*** - * The ascii transfer mode. Its value is 0 and equivalent to NETASCII_MODE - ***/ - public static final int ASCII_MODE = 0; - - /*** - * The netascii transfer mode. Its value is 0. - ***/ - public static final int NETASCII_MODE = 0; - - /*** - * The binary transfer mode. Its value is 1 and equivalent to OCTET_MODE. - ***/ - public static final int BINARY_MODE = 1; - - /*** - * The image transfer mode. Its value is 1 and equivalent to OCTET_MODE. - ***/ - public static final int IMAGE_MODE = 1; - - /*** - * The octet transfer mode. Its value is 1. - ***/ - public static final int OCTET_MODE = 1; - - /*** - * The default number of milliseconds to wait to receive a datagram - * before timing out. The default is 5000 milliseconds (5 seconds). - ***/ - public static final int DEFAULT_TIMEOUT = 5000; - - /*** - * The default TFTP port according to RFC 783 is 69. - ***/ - public static final int DEFAULT_PORT = 69; - - /*** - * The size to use for TFTP packet buffers. Its 4 plus the - * TFTPPacket.SEGMENT_SIZE, i.e. 516. - ***/ - static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4; - - /*** A buffer used to accelerate receives in bufferedReceive() ***/ - private byte[] __receiveBuffer; - - /*** A datagram used to minimize memory allocation in bufferedReceive() ***/ - private DatagramPacket __receiveDatagram; - - /*** A datagram used to minimize memory allocation in bufferedSend() ***/ - private DatagramPacket __sendDatagram; - - /*** - * A buffer used to accelerate sends in bufferedSend(). - * It is left package visible so that TFTPClient may be slightly more - * efficient during file sends. It saves the creation of an - * additional buffer and prevents a buffer copy in _newDataPcket(). - ***/ - byte[] _sendBuffer; - - - /*** - * Returns the TFTP string representation of a TFTP transfer mode. - * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer - * mode is specified. - *

- * @param mode The TFTP transfer mode. One of the MODE constants. - * @return The TFTP string representation of the TFTP transfer mode. - ***/ - public static final String getModeName(int mode) - { - return TFTPRequestPacket._modeStrings[mode]; - } - - /*** - * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT, - * a null socket, and buffered operations disabled. - ***/ - public TFTP() - { - setDefaultTimeout(DEFAULT_TIMEOUT); - __receiveBuffer = null; - __receiveDatagram = null; - } - - /*** - * This method synchronizes a connection by discarding all packets that - * may be in the local socket buffer. This method need only be called - * when you implement your own TFTP client or server. - *

- * @exception IOException if an I/O error occurs. - ***/ - public final void discardPackets() throws IOException - { - int to; - DatagramPacket datagram; - - datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE); - - to = getSoTimeout(); - setSoTimeout(1); - - try - { - while (true) - _socket_.receive(datagram); - } - catch (SocketException e) - { - // Do nothing. We timed out so we hope we're caught up. - } - catch (InterruptedIOException e) - { - // Do nothing. We timed out so we hope we're caught up. - } - - setSoTimeout(to); - } - - - /*** - * This is a special method to perform a more efficient packet receive. - * It should only be used after calling - * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps() - * initializes a set of buffers used internally that prevent the new - * allocation of a DatagramPacket and byte array for each send and receive. - * To use these buffers you must call the bufferedReceive() and - * bufferedSend() methods instead of send() and receive(). You must - * also be certain that you don't manipulate the resulting packet in - * such a way that it interferes with future buffered operations. - * For example, a TFTPDataPacket received with bufferedReceive() will - * have a reference to the internal byte buffer. You must finish using - * this data before calling bufferedReceive() again, or else the data - * will be overwritten by the the call. - *

- * @return The TFTPPacket received. - * @exception InterruptedIOException If a socket timeout occurs. The - * Java documentation claims an InterruptedIOException is thrown - * on a DatagramSocket timeout, but in practice we find a - * SocketException is thrown. You should catch both to be safe. - * @exception SocketException If a socket timeout occurs. The - * Java documentation claims an InterruptedIOException is thrown - * on a DatagramSocket timeout, but in practice we find a - * SocketException is thrown. You should catch both to be safe. - * @exception IOException If some other I/O error occurs. - * @exception TFTPPacketException If an invalid TFTP packet is received. - ***/ - public final TFTPPacket bufferedReceive() throws IOException, - InterruptedIOException, SocketException, TFTPPacketException - { - __receiveDatagram.setData(__receiveBuffer); - __receiveDatagram.setLength(__receiveBuffer.length); - _socket_.receive(__receiveDatagram); - - return TFTPPacket.newTFTPPacket(__receiveDatagram); - } - - /*** - * This is a special method to perform a more efficient packet send. - * It should only be used after calling - * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps() - * initializes a set of buffers used internally that prevent the new - * allocation of a DatagramPacket and byte array for each send and receive. - * To use these buffers you must call the bufferedReceive() and - * bufferedSend() methods instead of send() and receive(). You must - * also be certain that you don't manipulate the resulting packet in - * such a way that it interferes with future buffered operations. - * For example, a TFTPDataPacket received with bufferedReceive() will - * have a reference to the internal byte buffer. You must finish using - * this data before calling bufferedReceive() again, or else the data - * will be overwritten by the the call. - *

- * @param packet The TFTP packet to send. - * @exception IOException If some I/O error occurs. - ***/ - public final void bufferedSend(TFTPPacket packet) throws IOException - { - _socket_.send(packet._newDatagram(__sendDatagram, _sendBuffer)); - } - - - /*** - * Initializes the internal buffers. Buffers are used by - * {@link #bufferedSend bufferedSend() } and - * {@link #bufferedReceive bufferedReceive() }. This - * method must be called before calling either one of those two - * methods. When you finish using buffered operations, you must - * call {@link #endBufferedOps endBufferedOps() }. - ***/ - public final void beginBufferedOps() - { - __receiveBuffer = new byte[PACKET_SIZE]; - __receiveDatagram = - new DatagramPacket(__receiveBuffer, __receiveBuffer.length); - _sendBuffer = new byte[PACKET_SIZE]; - __sendDatagram = - new DatagramPacket(_sendBuffer, _sendBuffer.length); - } - - /*** - * Releases the resources used to perform buffered sends and receives. - ***/ - public final void endBufferedOps() - { - __receiveBuffer = null; - __receiveDatagram = null; - _sendBuffer = null; - __sendDatagram = null; - } - - - /*** - * Sends a TFTP packet to its destination. - *

- * @param packet The TFTP packet to send. - * @exception IOException If some I/O error occurs. - ***/ - public final void send(TFTPPacket packet) throws IOException - { - _socket_.send(packet.newDatagram()); - } - - - /*** - * Receives a TFTPPacket. - *

- * @return The TFTPPacket received. - * @exception InterruptedIOException If a socket timeout occurs. The - * Java documentation claims an InterruptedIOException is thrown - * on a DatagramSocket timeout, but in practice we find a - * SocketException is thrown. You should catch both to be safe. - * @exception SocketException If a socket timeout occurs. The - * Java documentation claims an InterruptedIOException is thrown - * on a DatagramSocket timeout, but in practice we find a - * SocketException is thrown. You should catch both to be safe. - * @exception IOException If some other I/O error occurs. - * @exception TFTPPacketException If an invalid TFTP packet is received. - ***/ - public final TFTPPacket receive() throws IOException, InterruptedIOException, - SocketException, TFTPPacketException - { - DatagramPacket packet; - - packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE); - - _socket_.receive(packet); - - return TFTPPacket.newTFTPPacket(packet); - } - - -} diff --git a/org/apache/commons/net/tftp/TFTPAckPacket.java b/org/apache/commons/net/tftp/TFTPAckPacket.java deleted file mode 100644 index a0fe7f9..0000000 --- a/org/apache/commons/net/tftp/TFTPAckPacket.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * A final class derived from TFTPPacket definiing the TFTP Acknowledgement - * packet type. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTPPacketException - * @see TFTP - ***/ - -public final class TFTPAckPacket extends TFTPPacket -{ - /*** The block number being acknowledged by the packet. ***/ - int _blockNumber; - - /*** - * Creates an acknowledgment packet to be sent to a host at a given port - * acknowledging receipt of a block. - *

- * @param destination The host to which the packet is going to be sent. - * @param port The port to which the packet is going to be sent. - * @param blockNumber The block number being acknowledged. - ***/ - public TFTPAckPacket(InetAddress destination, int port, int blockNumber) - { - super(TFTPPacket.ACKNOWLEDGEMENT, destination, port); - _blockNumber = blockNumber; - } - - /*** - * Creates an acknowledgement packet based from a received - * datagram. Assumes the datagram is at least length 4, else an - * ArrayIndexOutOfBoundsException may be thrown. - *

- * @param datagram The datagram containing the received acknowledgement. - * @throws TFTPPacketException If the datagram isn't a valid TFTP - * acknowledgement packet. - ***/ - TFTPAckPacket(DatagramPacket datagram) throws TFTPPacketException - { - super(TFTPPacket.ACKNOWLEDGEMENT, datagram.getAddress(), - datagram.getPort()); - byte[] data; - - data = datagram.getData(); - - if (getType() != data[1]) - throw new TFTPPacketException("TFTP operator code does not match type."); - - _blockNumber = (((data[2] & 0xff) << 8) | (data[3] & 0xff)); - } - - /*** - * This is a method only available within the package for - * implementing efficient datagram transport by elminating buffering. - * It takes a datagram as an argument, and a byte buffer in which - * to store the raw datagram data. Inside the method, the data - * is set as the datagram's data and the datagram returned. - *

- * @param datagram The datagram to create. - * @param data The buffer to store the packet and to use in the datagram. - * @return The datagram argument. - ***/ - @Override - DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) - { - data[0] = 0; - data[1] = (byte)_type; - data[2] = (byte)((_blockNumber & 0xffff) >> 8); - data[3] = (byte)(_blockNumber & 0xff); - - datagram.setAddress(_address); - datagram.setPort(_port); - datagram.setData(data); - datagram.setLength(4); - - return datagram; - } - - - /*** - * Creates a UDP datagram containing all the TFTP - * acknowledgement packet data in the proper format. - * This is a method exposed to the programmer in case he - * wants to implement his own TFTP client instead of using - * the {@link org.apache.commons.net.tftp.TFTPClient} - * class. Under normal circumstances, you should not have a need to call this - * method. - *

- * @return A UDP datagram containing the TFTP acknowledgement packet. - ***/ - @Override - public DatagramPacket newDatagram() - { - byte[] data; - - data = new byte[4]; - data[0] = 0; - data[1] = (byte)_type; - data[2] = (byte)((_blockNumber & 0xffff) >> 8); - data[3] = (byte)(_blockNumber & 0xff); - - return new DatagramPacket(data, data.length, _address, _port); - } - - - /*** - * Returns the block number of the acknowledgement. - *

- * @return The block number of the acknowledgement. - ***/ - public int getBlockNumber() - { - return _blockNumber; - } - - - /*** Sets the block number of the acknowledgement. ***/ - public void setBlockNumber(int blockNumber) - { - _blockNumber = blockNumber; - } -} - diff --git a/org/apache/commons/net/tftp/TFTPClient.java b/org/apache/commons/net/tftp/TFTPClient.java deleted file mode 100644 index 71d4ec6..0000000 --- a/org/apache/commons/net/tftp/TFTPClient.java +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import org.apache.commons.net.io.FromNetASCIIOutputStream; -import org.apache.commons.net.io.ToNetASCIIInputStream; - -/*** - * The TFTPClient class encapsulates all the aspects of the TFTP protocol - * necessary to receive and send files through TFTP. It is derived from - * the {@link org.apache.commons.net.tftp.TFTP} because - * it is more convenient than using aggregation, and as a result exposes - * the same set of methods to allow you to deal with the TFTP protocol - * directly. However, almost every user should only be concerend with the - * the {@link org.apache.commons.net.DatagramSocketClient#open open() }, - * {@link org.apache.commons.net.DatagramSocketClient#close close() }, - * {@link #sendFile sendFile() }, and - * {@link #receiveFile receiveFile() } methods. Additionally, the - * {@link #setMaxTimeouts setMaxTimeouts() } and - * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() } - * methods may be of importance for performance - * tuning. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. - *

- *

- * @author Daniel F. Savarese - * @see TFTP - * @see TFTPPacket - * @see TFTPPacketException - ***/ - -public class TFTPClient extends TFTP -{ - /*** - * The default number of times a receive attempt is allowed to timeout - * before ending attempts to retry the receive and failing. The default - * is 5 timeouts. - ***/ - public static final int DEFAULT_MAX_TIMEOUTS = 5; - - /*** The maximum number of timeouts allowed before failing. ***/ - private int __maxTimeouts; - - /*** - * Creates a TFTPClient instance with a default timeout of DEFAULT_TIMEOUT, - * maximum timeouts value of DEFAULT_MAX_TIMEOUTS, a null socket, - * and buffered operations disabled. - ***/ - public TFTPClient() - { - __maxTimeouts = DEFAULT_MAX_TIMEOUTS; - } - - /*** - * Sets the maximum number of times a receive attempt is allowed to - * timeout during a receiveFile() or sendFile() operation before ending - * attempts to retry the receive and failing. - * The default is DEFAULT_MAX_TIMEOUTS. - *

- * @param numTimeouts The maximum number of timeouts to allow. Values - * less than 1 should not be used, but if they are, they are - * treated as 1. - ***/ - public void setMaxTimeouts(int numTimeouts) - { - if (numTimeouts < 1) - __maxTimeouts = 1; - else - __maxTimeouts = numTimeouts; - } - - /*** - * Returns the maximum number of times a receive attempt is allowed to - * timeout before ending attempts to retry the receive and failing. - *

- * @return The maximum number of timeouts allowed. - ***/ - public int getMaxTimeouts() - { - return __maxTimeouts; - } - - - /*** - * Requests a named file from a remote host, writes the - * file to an OutputStream, closes the connection, and returns the number - * of bytes read. A local UDP socket must first be created by - * {@link org.apache.commons.net.DatagramSocketClient#open open()} before - * invoking this method. This method will not close the OutputStream - * containing the file; you must close it after the method invocation. - *

- * @param filename The name of the file to receive. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param output The OutputStream to which the file should be written. - * @param host The remote host serving the file. - * @param port The port number of the remote TFTP server. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - ***/ - public int receiveFile(String filename, int mode, OutputStream output, - InetAddress host, int port) throws IOException - { - int bytesRead, timeouts, lastBlock, block, hostPort, dataLength; - TFTPPacket sent, received = null; - TFTPErrorPacket error; - TFTPDataPacket data; - TFTPAckPacket ack = new TFTPAckPacket(host, port, 0); - - beginBufferedOps(); - - dataLength = lastBlock = hostPort = bytesRead = 0; - block = 1; - - if (mode == TFTP.ASCII_MODE) - output = new FromNetASCIIOutputStream(output); - - sent = - new TFTPReadRequestPacket(host, port, filename, mode); - -_sendPacket: - do - { - bufferedSend(sent); - -_receivePacket: - while (true) - { - timeouts = 0; - while (timeouts < __maxTimeouts) - { - try - { - received = bufferedReceive(); - break; - } - catch (SocketException e) - { - if (++timeouts >= __maxTimeouts) - { - endBufferedOps(); - throw new IOException("Connection timed out."); - } - continue; - } - catch (InterruptedIOException e) - { - if (++timeouts >= __maxTimeouts) - { - endBufferedOps(); - throw new IOException("Connection timed out."); - } - continue; - } - catch (TFTPPacketException e) - { - endBufferedOps(); - throw new IOException("Bad packet: " + e.getMessage()); - } - } - - // The first time we receive we get the port number and - // answering host address (for hosts with multiple IPs) - if (lastBlock == 0) - { - hostPort = received.getPort(); - ack.setPort(hostPort); - if(!host.equals(received.getAddress())) - { - host = received.getAddress(); - ack.setAddress(host); - sent.setAddress(host); - } - } - - // Comply with RFC 783 indication that an error acknowledgement - // should be sent to originator if unexpected TID or host. - if (host.equals(received.getAddress()) && - received.getPort() == hostPort) - { - - switch (received.getType()) - { - case TFTPPacket.ERROR: - error = (TFTPErrorPacket)received; - endBufferedOps(); - throw new IOException("Error code " + error.getError() + - " received: " + error.getMessage()); - case TFTPPacket.DATA: - data = (TFTPDataPacket)received; - dataLength = data.getDataLength(); - - lastBlock = data.getBlockNumber(); - - if (lastBlock == block) - { - try - { - output.write(data.getData(), data.getDataOffset(), - dataLength); - } - catch (IOException e) - { - error = new TFTPErrorPacket(host, hostPort, - TFTPErrorPacket.OUT_OF_SPACE, - "File write failed."); - bufferedSend(error); - endBufferedOps(); - throw e; - } - ++block; - if (block > 65535) - { - // wrap the block number - block = 0; - } - - break _receivePacket; - } - else - { - discardPackets(); - - if (lastBlock == (block == 0 ? 65535 : (block - 1))) - continue _sendPacket; // Resend last acknowledgement. - - continue _receivePacket; // Start fetching packets again. - } - //break; - - default: - endBufferedOps(); - throw new IOException("Received unexpected packet type."); - } - } - else - { - error = new TFTPErrorPacket(received.getAddress(), - received.getPort(), - TFTPErrorPacket.UNKNOWN_TID, - "Unexpected host or port."); - bufferedSend(error); - continue _sendPacket; - } - - // We should never get here, but this is a safety to avoid - // infinite loop. If only Java had the goto statement. - //break; - } - - ack.setBlockNumber(lastBlock); - sent = ack; - bytesRead += dataLength; - } // First data packet less than 512 bytes signals end of stream. - - while (dataLength == TFTPPacket.SEGMENT_SIZE); - - bufferedSend(sent); - endBufferedOps(); - - return bytesRead; - } - - - /*** - * Requests a named file from a remote host, writes the - * file to an OutputStream, closes the connection, and returns the number - * of bytes read. A local UDP socket must first be created by - * {@link org.apache.commons.net.DatagramSocketClient#open open()} before - * invoking this method. This method will not close the OutputStream - * containing the file; you must close it after the method invocation. - *

- * @param filename The name of the file to receive. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param output The OutputStream to which the file should be written. - * @param hostname The name of the remote host serving the file. - * @param port The port number of the remote TFTP server. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - * @exception UnknownHostException If the hostname cannot be resolved. - ***/ - public int receiveFile(String filename, int mode, OutputStream output, - String hostname, int port) - throws UnknownHostException, IOException - { - return receiveFile(filename, mode, output, InetAddress.getByName(hostname), - port); - } - - - /*** - * Same as calling receiveFile(filename, mode, output, host, TFTP.DEFAULT_PORT). - * - * @param filename The name of the file to receive. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param output The OutputStream to which the file should be written. - * @param host The remote host serving the file. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - ***/ - public int receiveFile(String filename, int mode, OutputStream output, - InetAddress host) - throws IOException - { - return receiveFile(filename, mode, output, host, DEFAULT_PORT); - } - - /*** - * Same as calling receiveFile(filename, mode, output, hostname, TFTP.DEFAULT_PORT). - * - * @param filename The name of the file to receive. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param output The OutputStream to which the file should be written. - * @param hostname The name of the remote host serving the file. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - * @exception UnknownHostException If the hostname cannot be resolved. - ***/ - public int receiveFile(String filename, int mode, OutputStream output, - String hostname) - throws UnknownHostException, IOException - { - return receiveFile(filename, mode, output, InetAddress.getByName(hostname), - DEFAULT_PORT); - } - - - /*** - * Requests to send a file to a remote host, reads the file from an - * InputStream, sends the file to the remote host, and closes the - * connection. A local UDP socket must first be created by - * {@link org.apache.commons.net.DatagramSocketClient#open open()} before - * invoking this method. This method will not close the InputStream - * containing the file; you must close it after the method invocation. - *

- * @param filename The name the remote server should use when creating - * the file on its file system. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param host The remote host receiving the file. - * @param port The port number of the remote TFTP server. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - ***/ - public void sendFile(String filename, int mode, InputStream input, - InetAddress host, int port) throws IOException - { - int bytesRead, timeouts, lastBlock, block, hostPort, dataLength, offset, totalThisPacket; - TFTPPacket sent, received = null; - TFTPErrorPacket error; - TFTPDataPacket data = - new TFTPDataPacket(host, port, 0, _sendBuffer, 4, 0); - TFTPAckPacket ack; - - boolean justStarted = true; - - beginBufferedOps(); - - dataLength = lastBlock = hostPort = bytesRead = totalThisPacket = 0; - block = 0; - boolean lastAckWait = false; - - if (mode == TFTP.ASCII_MODE) - input = new ToNetASCIIInputStream(input); - - sent = - new TFTPWriteRequestPacket(host, port, filename, mode); - -_sendPacket: - do - { - // first time: block is 0, lastBlock is 0, send a request packet. - // subsequent: block is integer starting at 1, send data packet. - bufferedSend(sent); - - // this is trying to receive an ACK -_receivePacket: - while (true) - { - - - timeouts = 0; - while (timeouts < __maxTimeouts) - { - try - { - received = bufferedReceive(); - break; - } - catch (SocketException e) - { - if (++timeouts >= __maxTimeouts) - { - endBufferedOps(); - throw new IOException("Connection timed out."); - } - continue; - } - catch (InterruptedIOException e) - { - if (++timeouts >= __maxTimeouts) - { - endBufferedOps(); - throw new IOException("Connection timed out."); - } - continue; - } - catch (TFTPPacketException e) - { - endBufferedOps(); - throw new IOException("Bad packet: " + e.getMessage()); - } - } // end of while loop over tries to receive - - // The first time we receive we get the port number and - // answering host address (for hosts with multiple IPs) - if (justStarted) - { - justStarted = false; - hostPort = received.getPort(); - data.setPort(hostPort); - if(!host.equals(received.getAddress())) - { - host = received.getAddress(); - data.setAddress(host); - sent.setAddress(host); - } - } - - // Comply with RFC 783 indication that an error acknowledgement - // should be sent to originator if unexpected TID or host. - if (host.equals(received.getAddress()) && - received.getPort() == hostPort) - { - - switch (received.getType()) - { - case TFTPPacket.ERROR: - error = (TFTPErrorPacket)received; - endBufferedOps(); - throw new IOException("Error code " + error.getError() + - " received: " + error.getMessage()); - case TFTPPacket.ACKNOWLEDGEMENT: - ack = (TFTPAckPacket)received; - - lastBlock = ack.getBlockNumber(); - - if (lastBlock == block) - { - ++block; - if (block > 65535) - { - // wrap the block number - block = 0; - } - if (lastAckWait) { - - break _sendPacket; - } - else { - break _receivePacket; - } - } - else - { - discardPackets(); - - if (lastBlock == (block == 0 ? 65535 : (block - 1))) - continue _sendPacket; // Resend last acknowledgement. - - continue _receivePacket; // Start fetching packets again. - } - //break; - - default: - endBufferedOps(); - throw new IOException("Received unexpected packet type."); - } - } - else - { - error = new TFTPErrorPacket(received.getAddress(), - received.getPort(), - TFTPErrorPacket.UNKNOWN_TID, - "Unexpected host or port."); - bufferedSend(error); - continue _sendPacket; - } - - // We should never get here, but this is a safety to avoid - // infinite loop. If only Java had the goto statement. - //break; - } - - // OK, we have just gotten ACK about the last data we sent. Make another - // and send it - - dataLength = TFTPPacket.SEGMENT_SIZE; - offset = 4; - totalThisPacket = 0; - while (dataLength > 0 && - (bytesRead = input.read(_sendBuffer, offset, dataLength)) > 0) - { - offset += bytesRead; - dataLength -= bytesRead; - totalThisPacket += bytesRead; - } - - if( totalThisPacket < TFTPPacket.SEGMENT_SIZE ) { - /* this will be our last packet -- send, wait for ack, stop */ - lastAckWait = true; - } - data.setBlockNumber(block); - data.setData(_sendBuffer, 4, totalThisPacket); - sent = data; - } - while ( totalThisPacket > 0 || lastAckWait ); - // Note: this was looping while dataLength == 0 || lastAckWait, - // which was discarding the last packet if it was not full size - // Should send the packet. - - endBufferedOps(); - } - - - /*** - * Requests to send a file to a remote host, reads the file from an - * InputStream, sends the file to the remote host, and closes the - * connection. A local UDP socket must first be created by - * {@link org.apache.commons.net.DatagramSocketClient#open open()} before - * invoking this method. This method will not close the InputStream - * containing the file; you must close it after the method invocation. - *

- * @param filename The name the remote server should use when creating - * the file on its file system. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param hostname The name of the remote host receiving the file. - * @param port The port number of the remote TFTP server. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - * @exception UnknownHostException If the hostname cannot be resolved. - ***/ - public void sendFile(String filename, int mode, InputStream input, - String hostname, int port) - throws UnknownHostException, IOException - { - sendFile(filename, mode, input, InetAddress.getByName(hostname), port); - } - - - /*** - * Same as calling sendFile(filename, mode, input, host, TFTP.DEFAULT_PORT). - * - * @param filename The name the remote server should use when creating - * the file on its file system. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param host The name of the remote host receiving the file. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - * @exception UnknownHostException If the hostname cannot be resolved. - ***/ - public void sendFile(String filename, int mode, InputStream input, - InetAddress host) - throws IOException - { - sendFile(filename, mode, input, host, DEFAULT_PORT); - } - - /*** - * Same as calling sendFile(filename, mode, input, hostname, TFTP.DEFAULT_PORT). - * - * @param filename The name the remote server should use when creating - * the file on its file system. - * @param mode The TFTP mode of the transfer (one of the MODE constants). - * @param hostname The name of the remote host receiving the file. - * @exception IOException If an I/O error occurs. The nature of the - * error will be reported in the message. - * @exception UnknownHostException If the hostname cannot be resolved. - ***/ - public void sendFile(String filename, int mode, InputStream input, - String hostname) - throws UnknownHostException, IOException - { - sendFile(filename, mode, input, InetAddress.getByName(hostname), - DEFAULT_PORT); - } -} diff --git a/org/apache/commons/net/tftp/TFTPDataPacket.java b/org/apache/commons/net/tftp/TFTPDataPacket.java deleted file mode 100644 index 24c0dd3..0000000 --- a/org/apache/commons/net/tftp/TFTPDataPacket.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * A final class derived from TFTPPacket definiing the TFTP Data - * packet type. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTPPacketException - * @see TFTP - ***/ - -public final class TFTPDataPacket extends TFTPPacket -{ - /*** The maximum number of bytes in a TFTP data packet (512) ***/ - public static final int MAX_DATA_LENGTH = 512; - - /*** The minimum number of bytes in a TFTP data packet (0) ***/ - public static final int MIN_DATA_LENGTH = 0; - - /*** The block number of the packet. ***/ - int _blockNumber; - - /*** The length of the data. ***/ - int _length; - - /*** The offset into the _data array at which the data begins. ***/ - int _offset; - - /*** The data stored in the packet. ***/ - byte[] _data; - - /*** - * Creates a data packet to be sent to a host at a given port - * with a given block number. The actual data to be sent is passed as - * an array, an offset, and a length. The offset is the offset into - * the byte array where the data starts. The length is the length of - * the data. If the length is greater than MAX_DATA_LENGTH, it is - * truncated. - *

- * @param destination The host to which the packet is going to be sent. - * @param port The port to which the packet is going to be sent. - * @param blockNumber The block number of the data. - * @param data The byte array containing the data. - * @param offset The offset into the array where the data starts. - * @param length The length of the data. - ***/ - public TFTPDataPacket(InetAddress destination, int port, int blockNumber, - byte[] data, int offset, int length) - { - super(TFTPPacket.DATA, destination, port); - - _blockNumber = blockNumber; - _data = data; - _offset = offset; - - if (length > MAX_DATA_LENGTH) - _length = MAX_DATA_LENGTH; - else - _length = length; - } - - public TFTPDataPacket(InetAddress destination, int port, int blockNumber, - byte[] data) - { - this(destination, port, blockNumber, data, 0, data.length); - } - - - /*** - * Creates a data packet based from a received - * datagram. Assumes the datagram is at least length 4, else an - * ArrayIndexOutOfBoundsException may be thrown. - *

- * @param datagram The datagram containing the received data. - * @throws TFTPPacketException If the datagram isn't a valid TFTP - * data packet. - ***/ - TFTPDataPacket(DatagramPacket datagram) throws TFTPPacketException - { - super(TFTPPacket.DATA, datagram.getAddress(), datagram.getPort()); - - _data = datagram.getData(); - _offset = 4; - - if (getType() != _data[1]) - throw new TFTPPacketException("TFTP operator code does not match type."); - - _blockNumber = (((_data[2] & 0xff) << 8) | (_data[3] & 0xff)); - - _length = datagram.getLength() - 4; - - if (_length > MAX_DATA_LENGTH) - _length = MAX_DATA_LENGTH; - } - - /*** - * This is a method only available within the package for - * implementing efficient datagram transport by elminating buffering. - * It takes a datagram as an argument, and a byte buffer in which - * to store the raw datagram data. Inside the method, the data - * is set as the datagram's data and the datagram returned. - *

- * @param datagram The datagram to create. - * @param data The buffer to store the packet and to use in the datagram. - * @return The datagram argument. - ***/ - @Override - DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) - { - data[0] = 0; - data[1] = (byte)_type; - data[2] = (byte)((_blockNumber & 0xffff) >> 8); - data[3] = (byte)(_blockNumber & 0xff); - - // Doublecheck we're not the same - if (data != _data) - System.arraycopy(_data, _offset, data, 4, _length); - - datagram.setAddress(_address); - datagram.setPort(_port); - datagram.setData(data); - datagram.setLength(_length + 4); - - return datagram; - } - - /*** - * Creates a UDP datagram containing all the TFTP - * data packet data in the proper format. - * This is a method exposed to the programmer in case he - * wants to implement his own TFTP client instead of using - * the {@link org.apache.commons.net.tftp.TFTPClient} - * class. - * Under normal circumstances, you should not have a need to call this - * method. - *

- * @return A UDP datagram containing the TFTP data packet. - ***/ - @Override - public DatagramPacket newDatagram() - { - byte[] data; - - data = new byte[_length + 4]; - data[0] = 0; - data[1] = (byte)_type; - data[2] = (byte)((_blockNumber & 0xffff) >> 8); - data[3] = (byte)(_blockNumber & 0xff); - - System.arraycopy(_data, _offset, data, 4, _length); - - return new DatagramPacket(data, _length + 4, _address, _port); - } - - /*** - * Returns the block number of the data packet. - *

- * @return The block number of the data packet. - ***/ - public int getBlockNumber() - { - return _blockNumber; - } - - /*** Sets the block number of the data packet. ***/ - public void setBlockNumber(int blockNumber) - { - _blockNumber = blockNumber; - } - - /*** - * Sets the data for the data packet. - *

- * @param data The byte array containing the data. - * @param offset The offset into the array where the data starts. - * @param length The length of the data. - ***/ - public void setData(byte[] data, int offset, int length) - { - _data = data; - _offset = offset; - _length = length; - - if (length > MAX_DATA_LENGTH) - _length = MAX_DATA_LENGTH; - else - _length = length; - } - - /*** - * Returns the length of the data part of the data packet. - *

- * @return The length of the data part of the data packet. - ***/ - public int getDataLength() - { - return _length; - } - - /*** - * Returns the offset into the byte array where the packet data actually - * starts. - *

- * @return The offset into the byte array where the packet data actually - * starts. - ***/ - public int getDataOffset() - { - return _offset; - } - - /*** - * Returns the byte array containing the packet data. - *

- * @return The byte array containing the packet data. - ***/ - public byte[] getData() - { - return _data; - } -} diff --git a/org/apache/commons/net/tftp/TFTPErrorPacket.java b/org/apache/commons/net/tftp/TFTPErrorPacket.java deleted file mode 100644 index 2e7aec2..0000000 --- a/org/apache/commons/net/tftp/TFTPErrorPacket.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * A final class derived from TFTPPacket definiing the TFTP Error - * packet type. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTPPacketException - * @see TFTP - ***/ - -public final class TFTPErrorPacket extends TFTPPacket -{ - /*** The undefined error code according to RFC 783, value 0. ***/ - public static final int UNDEFINED = 0; - - /*** The file not found error code according to RFC 783, value 1. ***/ - public static final int FILE_NOT_FOUND = 1; - - /*** The access violation error code according to RFC 783, value 2. ***/ - public static final int ACCESS_VIOLATION = 2; - - /*** The disk full error code according to RFC 783, value 3. ***/ - public static final int OUT_OF_SPACE = 3; - - /*** - * The illegal TFTP operation error code according to RFC 783, value 4. - ***/ - public static final int ILLEGAL_OPERATION = 4; - - /*** The unknown transfer id error code according to RFC 783, value 5. ***/ - public static final int UNKNOWN_TID = 5; - - /*** The file already exists error code according to RFC 783, value 6. ***/ - public static final int FILE_EXISTS = 6; - - /*** The no such user error code according to RFC 783, value 7. ***/ - public static final int NO_SUCH_USER = 7; - - /*** The error code of this packet. ***/ - int _error; - - /*** The error message of this packet. ***/ - String _message; - - /*** - * Creates an error packet to be sent to a host at a given port - * with an error code and error message. - *

- * @param destination The host to which the packet is going to be sent. - * @param port The port to which the packet is going to be sent. - * @param error The error code of the packet. - * @param message The error message of the packet. - ***/ - public TFTPErrorPacket(InetAddress destination, int port, - int error, String message) - { - super(TFTPPacket.ERROR, destination, port); - - _error = error; - _message = message; - } - - /*** - * Creates an error packet based from a received - * datagram. Assumes the datagram is at least length 4, else an - * ArrayIndexOutOfBoundsException may be thrown. - *

- * @param datagram The datagram containing the received error. - * @throws TFTPPacketException If the datagram isn't a valid TFTP - * error packet. - ***/ - TFTPErrorPacket(DatagramPacket datagram) throws TFTPPacketException - { - super(TFTPPacket.ERROR, datagram.getAddress(), datagram.getPort()); - int index, length; - byte[] data; - StringBuffer buffer; - - data = datagram.getData(); - length = datagram.getLength(); - - if (getType() != data[1]) - throw new TFTPPacketException("TFTP operator code does not match type."); - - _error = (((data[2] & 0xff) << 8) | (data[3] & 0xff)); - - if (length < 5) - throw new TFTPPacketException("Bad error packet. No message."); - - index = 4; - buffer = new StringBuffer(); - - while (index < length && data[index] != 0) - { - buffer.append((char)data[index]); - ++index; - } - - _message = buffer.toString(); - } - - /*** - * This is a method only available within the package for - * implementing efficient datagram transport by elminating buffering. - * It takes a datagram as an argument, and a byte buffer in which - * to store the raw datagram data. Inside the method, the data - * is set as the datagram's data and the datagram returned. - *

- * @param datagram The datagram to create. - * @param data The buffer to store the packet and to use in the datagram. - * @return The datagram argument. - ***/ - @Override - DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) - { - int length; - - length = _message.length(); - - data[0] = 0; - data[1] = (byte)_type; - data[2] = (byte)((_error & 0xffff) >> 8); - data[3] = (byte)(_error & 0xff); - - System.arraycopy(_message.getBytes(), 0, data, 4, length); - - data[length + 4] = 0; - - datagram.setAddress(_address); - datagram.setPort(_port); - datagram.setData(data); - datagram.setLength(length + 4); - - return datagram; - } - - - /*** - * Creates a UDP datagram containing all the TFTP - * error packet data in the proper format. - * This is a method exposed to the programmer in case he - * wants to implement his own TFTP client instead of using - * the {@link org.apache.commons.net.tftp.TFTPClient} - * class. - * Under normal circumstances, you should not have a need to call this - * method. - *

- * @return A UDP datagram containing the TFTP error packet. - ***/ - @Override - public DatagramPacket newDatagram() - { - byte[] data; - int length; - - length = _message.length(); - - data = new byte[length + 5]; - data[0] = 0; - data[1] = (byte)_type; - data[2] = (byte)((_error & 0xffff) >> 8); - data[3] = (byte)(_error & 0xff); - - System.arraycopy(_message.getBytes(), 0, data, 4, length); - - data[length + 4] = 0; - - return new DatagramPacket(data, data.length, _address, _port); - } - - - /*** - * Returns the error code of the packet. - *

- * @return The error code of the packet. - ***/ - public int getError() - { - return _error; - } - - - /*** - * Returns the error message of the packet. - *

- * @return The error message of the packet. - ***/ - public String getMessage() - { - return _message; - } -} diff --git a/org/apache/commons/net/tftp/TFTPPacket.java b/org/apache/commons/net/tftp/TFTPPacket.java deleted file mode 100644 index e1dc5f1..0000000 --- a/org/apache/commons/net/tftp/TFTPPacket.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * TFTPPacket is an abstract class encapsulating the functionality common - * to the 5 types of TFTP packets. It also provides a static factory - * method that will create the correct TFTP packet instance from a - * datagram. This relieves the programmer from having to figure out what - * kind of TFTP packet is contained in a datagram and create it himself. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacketException - * @see TFTP - ***/ - -public abstract class TFTPPacket -{ - /*** - * The minimum size of a packet. This is 4 bytes. It is enough - * to store the opcode and blocknumber or other required data - * depending on the packet type. - ***/ - static final int MIN_PACKET_SIZE = 4; - - /*** - * This is the actual TFTP spec - * identifier and is equal to 1. - * Identifier returned by {@link #getType getType()} - * indicating a read request packet. - ***/ - public static final int READ_REQUEST = 1; - - /*** - * This is the actual TFTP spec - * identifier and is equal to 2. - * Identifier returned by {@link #getType getType()} - * indicating a write request packet. - ***/ - public static final int WRITE_REQUEST = 2; - - /*** - * This is the actual TFTP spec - * identifier and is equal to 3. - * Identifier returned by {@link #getType getType()} - * indicating a data packet. - ***/ - public static final int DATA = 3; - - /*** - * This is the actual TFTP spec - * identifier and is equal to 4. - * Identifier returned by {@link #getType getType()} - * indicating an acknowledgement packet. - ***/ - public static final int ACKNOWLEDGEMENT = 4; - - /*** - * This is the actual TFTP spec - * identifier and is equal to 5. - * Identifier returned by {@link #getType getType()} - * indicating an error packet. - ***/ - public static final int ERROR = 5; - - /*** - * The TFTP data packet maximum segment size in bytes. This is 512 - * and is useful for those familiar with the TFTP protocol who want - * to use the {@link org.apache.commons.net.tftp.TFTP} - * class methods to implement their own TFTP servers or clients. - ***/ - public static final int SEGMENT_SIZE = 512; - - /*** The type of packet. ***/ - int _type; - - /*** The port the packet came from or is going to. ***/ - int _port; - - /*** The host the packet is going to be sent or where it came from. ***/ - InetAddress _address; - - /*** - * When you receive a datagram that you expect to be a TFTP packet, you use - * this factory method to create the proper TFTPPacket object - * encapsulating the data contained in that datagram. This method is the - * only way you can instantiate a TFTPPacket derived class from a - * datagram. - *

- * @param datagram The datagram containing a TFTP packet. - * @return The TFTPPacket object corresponding to the datagram. - * @exception TFTPPacketException If the datagram does not contain a valid - * TFTP packet. - ***/ - public final static TFTPPacket newTFTPPacket(DatagramPacket datagram) - throws TFTPPacketException - { - byte[] data; - TFTPPacket packet = null; - - if (datagram.getLength() < MIN_PACKET_SIZE) - throw new TFTPPacketException( - "Bad packet. Datagram data length is too short."); - - data = datagram.getData(); - - switch (data[1]) - { - case READ_REQUEST: - packet = new TFTPReadRequestPacket(datagram); - break; - case WRITE_REQUEST: - packet = new TFTPWriteRequestPacket(datagram); - break; - case DATA: - packet = new TFTPDataPacket(datagram); - break; - case ACKNOWLEDGEMENT: - packet = new TFTPAckPacket(datagram); - break; - case ERROR: - packet = new TFTPErrorPacket(datagram); - break; - default: - throw new TFTPPacketException( - "Bad packet. Invalid TFTP operator code."); - } - - return packet; - } - - /*** - * This constructor is not visible outside of the package. It is used - * by subclasses within the package to initialize base data. - *

- * @param type The type of the packet. - * @param address The host the packet came from or is going to be sent. - * @param port The port the packet came from or is going to be sent. - **/ - TFTPPacket(int type, InetAddress address, int port) - { - _type = type; - _address = address; - _port = port; - } - - /*** - * This is an abstract method only available within the package for - * implementing efficient datagram transport by elminating buffering. - * It takes a datagram as an argument, and a byte buffer in which - * to store the raw datagram data. Inside the method, the data - * should be set as the datagram's data and the datagram returned. - *

- * @param datagram The datagram to create. - * @param data The buffer to store the packet and to use in the datagram. - * @return The datagram argument. - ***/ - abstract DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data); - - /*** - * Creates a UDP datagram containing all the TFTP packet - * data in the proper format. - * This is an abstract method, exposed to the programmer in case he - * wants to implement his own TFTP client instead of using - * the {@link org.apache.commons.net.tftp.TFTPClient} - * class. - * Under normal circumstances, you should not have a need to call this - * method. - *

- * @return A UDP datagram containing the TFTP packet. - ***/ - public abstract DatagramPacket newDatagram(); - - /*** - * Returns the type of the packet. - *

- * @return The type of the packet. - ***/ - public final int getType() - { - return _type; - } - - /*** - * Returns the address of the host where the packet is going to be sent - * or where it came from. - *

- * @return The type of the packet. - ***/ - public final InetAddress getAddress() - { - return _address; - } - - /*** - * Returns the port where the packet is going to be sent - * or where it came from. - *

- * @return The port where the packet came from or where it is going. - ***/ - public final int getPort() - { - return _port; - } - - /*** Sets the port where the packet is going to be sent. ***/ - public final void setPort(int port) - { - _port = port; - } - - /*** Sets the host address where the packet is going to be sent. ***/ - public final void setAddress(InetAddress address) - { - _address = address; - } -} diff --git a/org/apache/commons/net/tftp/TFTPPacketException.java b/org/apache/commons/net/tftp/TFTPPacketException.java deleted file mode 100644 index 286fa3a..0000000 --- a/org/apache/commons/net/tftp/TFTPPacketException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -/*** - * A class used to signify the occurrence of an error in the creation of - * a TFTP packet. It is not declared final so that it may be subclassed - * to identify more specific errors. You would only want to do this if - * you were building your own TFTP client or server on top of the - * {@link org.apache.commons.net.tftp.TFTP} - * class if you - * wanted more functionality than the - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods provide. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTP - ***/ - -public class TFTPPacketException extends Exception -{ - - /*** - * Simply calls the corresponding constructor of its superclass. - ***/ - public TFTPPacketException() - { - super(); - } - - /*** - * Simply calls the corresponding constructor of its superclass. - ***/ - public TFTPPacketException(String message) - { - super(message); - } -} diff --git a/org/apache/commons/net/tftp/TFTPReadRequestPacket.java b/org/apache/commons/net/tftp/TFTPReadRequestPacket.java deleted file mode 100644 index 2669df6..0000000 --- a/org/apache/commons/net/tftp/TFTPReadRequestPacket.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * A class derived from TFTPRequestPacket definiing a TFTP read request - * packet type. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTPRequestPacket - * @see TFTPPacketException - * @see TFTP - ***/ - -public final class TFTPReadRequestPacket extends TFTPRequestPacket -{ - - /*** - * Creates a read request packet to be sent to a host at a - * given port with a filename and transfer mode request. - *

- * @param destination The host to which the packet is going to be sent. - * @param port The port to which the packet is going to be sent. - * @param filename The requested filename. - * @param mode The requested transfer mode. This should be on of the TFTP - * class MODE constants (e.g., TFTP.NETASCII_MODE). - ***/ - public TFTPReadRequestPacket(InetAddress destination, int port, - String filename, int mode) - { - super(destination, port, TFTPPacket.READ_REQUEST, filename, mode); - } - - /*** - * Creates a read request packet of based on a received - * datagram and assumes the datagram has already been identified as a - * read request. Assumes the datagram is at least length 4, else an - * ArrayIndexOutOfBoundsException may be thrown. - *

- * @param datagram The datagram containing the received request. - * @throws TFTPPacketException If the datagram isn't a valid TFTP - * request packet. - ***/ - TFTPReadRequestPacket(DatagramPacket datagram) throws TFTPPacketException - { - super(TFTPPacket.READ_REQUEST, datagram); - } - -} diff --git a/org/apache/commons/net/tftp/TFTPRequestPacket.java b/org/apache/commons/net/tftp/TFTPRequestPacket.java deleted file mode 100644 index a0f4407..0000000 --- a/org/apache/commons/net/tftp/TFTPRequestPacket.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * An abstract class derived from TFTPPacket definiing a TFTP Request - * packet type. It is subclassed by the - * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket} - * and - * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket} - * classes. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTPReadRequestPacket - * @see TFTPWriteRequestPacket - * @see TFTPPacketException - * @see TFTP - ***/ - -public abstract class TFTPRequestPacket extends TFTPPacket -{ - /*** - * An array containing the string names of the transfer modes and indexed - * by the transfer mode constants. - ***/ - static final String[] _modeStrings = { "netascii", "octet" }; - - /*** - * A null terminated byte array representation of the ascii names of the - * transfer mode constants. This is convenient for creating the TFTP - * request packets. - ***/ - static final byte[] _modeBytes[] = { - { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c', - (byte)'i', (byte)'i', 0 }, - { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 } - }; - - /*** The transfer mode of the request. ***/ - int _mode; - - /*** The filename of the request. ***/ - String _filename; - - /*** - * Creates a request packet of a given type to be sent to a host at a - * given port with a filename and transfer mode request. - *

- * @param destination The host to which the packet is going to be sent. - * @param port The port to which the packet is going to be sent. - * @param type The type of the request (either TFTPPacket.READ_REQUEST or - * TFTPPacket.WRITE_REQUEST). - * @param filename The requested filename. - * @param mode The requested transfer mode. This should be on of the TFTP - * class MODE constants (e.g., TFTP.NETASCII_MODE). - ***/ - TFTPRequestPacket(InetAddress destination, int port, - int type, String filename, int mode) - { - super(type, destination, port); - - _filename = filename; - _mode = mode; - } - - /*** - * Creates a request packet of a given type based on a received - * datagram. Assumes the datagram is at least length 4, else an - * ArrayIndexOutOfBoundsException may be thrown. - *

- * @param type The type of the request (either TFTPPacket.READ_REQUEST or - * TFTPPacket.WRITE_REQUEST). - * @param datagram The datagram containing the received request. - * @throws TFTPPacketException If the datagram isn't a valid TFTP - * request packet of the appropriate type. - ***/ - TFTPRequestPacket(int type, DatagramPacket datagram) - throws TFTPPacketException - { - super(type, datagram.getAddress(), datagram.getPort()); - - byte[] data; - int index, length; - String mode; - StringBuffer buffer; - - data = datagram.getData(); - - if (getType() != data[1]) - throw new TFTPPacketException("TFTP operator code does not match type."); - - buffer = new StringBuffer(); - - index = 2; - length = datagram.getLength(); - - while (index < length && data[index] != 0) - { - buffer.append((char)data[index]); - ++index; - } - - _filename = buffer.toString(); - - if (index >= length) - throw new TFTPPacketException("Bad filename and mode format."); - - buffer.setLength(0); - ++index; // need to advance beyond the end of string marker - while (index < length && data[index] != 0) - { - buffer.append((char)data[index]); - ++index; - } - - mode = buffer.toString().toLowerCase(java.util.Locale.ENGLISH); - length = _modeStrings.length; - - for (index = 0; index < length; index++) - { - if (mode.equals(_modeStrings[index])) - { - _mode = index; - break; - } - } - - if (index >= length) - { - throw new TFTPPacketException("Unrecognized TFTP transfer mode: " + mode); - // May just want to default to binary mode instead of throwing - // exception. - //_mode = TFTP.OCTET_MODE; - } - } - - - /*** - * This is a method only available within the package for - * implementing efficient datagram transport by elminating buffering. - * It takes a datagram as an argument, and a byte buffer in which - * to store the raw datagram data. Inside the method, the data - * is set as the datagram's data and the datagram returned. - *

- * @param datagram The datagram to create. - * @param data The buffer to store the packet and to use in the datagram. - * @return The datagram argument. - ***/ - @Override - final DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data) - { - int fileLength, modeLength; - - fileLength = _filename.length(); - modeLength = _modeBytes[_mode].length; - - data[0] = 0; - data[1] = (byte)_type; - System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength); - data[fileLength + 2] = 0; - System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3, - modeLength); - - datagram.setAddress(_address); - datagram.setPort(_port); - datagram.setData(data); - datagram.setLength(fileLength + modeLength + 3); - - return datagram; - } - - /*** - * Creates a UDP datagram containing all the TFTP - * request packet data in the proper format. - * This is a method exposed to the programmer in case he - * wants to implement his own TFTP client instead of using - * the {@link org.apache.commons.net.tftp.TFTPClient} - * class. Under normal circumstances, you should not have a need to call - * this method. - *

- * @return A UDP datagram containing the TFTP request packet. - ***/ - @Override - public final DatagramPacket newDatagram() - { - int fileLength, modeLength; - byte[] data; - - fileLength = _filename.length(); - modeLength = _modeBytes[_mode].length; - - data = new byte[fileLength + modeLength + 4]; - data[0] = 0; - data[1] = (byte)_type; - System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength); - data[fileLength + 2] = 0; - System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3, - modeLength); - - return new DatagramPacket(data, data.length, _address, _port); - } - - /*** - * Returns the transfer mode of the request. - *

- * @return The transfer mode of the request. - ***/ - public final int getMode() - { - return _mode; - } - - /*** - * Returns the requested filename. - *

- * @return The requested filename. - ***/ - public final String getFilename() - { - return _filename; - } -} diff --git a/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java b/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java deleted file mode 100644 index b545b2d..0000000 --- a/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.tftp; - -import java.net.DatagramPacket; -import java.net.InetAddress; - -/*** - * A class derived from TFTPRequestPacket definiing a TFTP write request - * packet type. - *

- * Details regarding the TFTP protocol and the format of TFTP packets can - * be found in RFC 783. But the point of these classes is to keep you - * from having to worry about the internals. Additionally, only very - * few people should have to care about any of the TFTPPacket classes - * or derived classes. Almost all users should only be concerned with the - * {@link org.apache.commons.net.tftp.TFTPClient} class - * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} - * and - * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} - * methods. - *

- *

- * @author Daniel F. Savarese - * @see TFTPPacket - * @see TFTPRequestPacket - * @see TFTPPacketException - * @see TFTP - ***/ - -public final class TFTPWriteRequestPacket extends TFTPRequestPacket -{ - - /*** - * Creates a write request packet to be sent to a host at a - * given port with a filename and transfer mode request. - *

- * @param destination The host to which the packet is going to be sent. - * @param port The port to which the packet is going to be sent. - * @param filename The requested filename. - * @param mode The requested transfer mode. This should be on of the TFTP - * class MODE constants (e.g., TFTP.NETASCII_MODE). - ***/ - public TFTPWriteRequestPacket(InetAddress destination, int port, - String filename, int mode) - { - super(destination, port, TFTPPacket.WRITE_REQUEST, filename, mode); - } - - /*** - * Creates a write request packet of based on a received - * datagram and assumes the datagram has already been identified as a - * write request. Assumes the datagram is at least length 4, else an - * ArrayIndexOutOfBoundsException may be thrown. - *

- * @param datagram The datagram containing the received request. - * @throws TFTPPacketException If the datagram isn't a valid TFTP - * request packet. - ***/ - TFTPWriteRequestPacket(DatagramPacket datagram) throws TFTPPacketException - { - super(TFTPPacket.WRITE_REQUEST, datagram); - } -} diff --git a/org/apache/commons/net/time/TimeTCPClient.java b/org/apache/commons/net/time/TimeTCPClient.java deleted file mode 100644 index ad10ba5..0000000 --- a/org/apache/commons/net/time/TimeTCPClient.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.time; - -import java.io.DataInputStream; -import java.io.IOException; -import java.util.Date; - -import org.apache.commons.net.SocketClient; - -/*** - * The TimeTCPClient class is a TCP implementation of a client for the - * Time protocol described in RFC 868. To use the class, merely - * establish a connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * and call either {@link #getTime getTime() } or - * {@link #getDate getDate() } to retrieve the time, then - * call {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * to close the connection properly. - *

- *

- * @author Daniel F. Savarese - * @see TimeUDPClient - ***/ - -public final class TimeTCPClient extends SocketClient -{ - /*** The default time port. It is set to 37 according to RFC 868. ***/ - public static final int DEFAULT_PORT = 37; - - /*** - * The number of seconds between 00:00 1 January 1900 and - * 00:00 1 January 1970. This value can be useful for converting - * time values to other formats. - ***/ - public static final long SECONDS_1900_TO_1970 = 2208988800L; - - /*** - * The default TimeTCPClient constructor. It merely sets the default - * port to DEFAULT_PORT . - ***/ - public TimeTCPClient () - { - setDefaultPort(DEFAULT_PORT); - } - - /*** - * Retrieves the time from the server and returns it. The time - * is the number of seconds since 00:00 (midnight) 1 January 1900 GMT, - * as specified by RFC 868. This method reads the raw 32-bit big-endian - * unsigned integer from the server, converts it to a Java long, and - * returns the value. - *

- * The server will have closed the connection at this point, so you should - * call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after calling this method. To retrieve another time, you must - * initiate another connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before calling getTime() again. - *

- * @return The time value retrieved from the server. - * @exception IOException If an error occurs while fetching the time. - ***/ - public long getTime() throws IOException - { - DataInputStream input; - input = new DataInputStream(_input_); - return (input.readInt() & 0xffffffffL); - } - - /*** - * Retrieves the time from the server and returns a Java Date - * containing the time converted to the local timezone. - *

- * The server will have closed the connection at this point, so you should - * call - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after calling this method. To retrieve another time, you must - * initiate another connection with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before calling getDate() again. - *

- * @return A Date value containing the time retrieved from the server - * converted to the local timezone. - * @exception IOException If an error occurs while fetching the time. - ***/ - public Date getDate() throws IOException - { - return new Date((getTime() - SECONDS_1900_TO_1970)*1000L); - } - -} - diff --git a/org/apache/commons/net/time/TimeUDPClient.java b/org/apache/commons/net/time/TimeUDPClient.java deleted file mode 100644 index f58d96e..0000000 --- a/org/apache/commons/net/time/TimeUDPClient.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.time; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; -import java.util.Date; - -import org.apache.commons.net.DatagramSocketClient; - -/*** - * The TimeUDPClient class is a UDP implementation of a client for the - * Time protocol described in RFC 868. To use the class, merely - * open a local datagram socket with - * {@link org.apache.commons.net.DatagramSocketClient#open open } - * and call {@link #getTime getTime } or - * {@link #getTime getDate } to retrieve the time. Then call - * {@link org.apache.commons.net.DatagramSocketClient#close close } - * to close the connection properly. Unlike - * {@link org.apache.commons.net.time.TimeTCPClient}, - * successive calls to {@link #getTime getTime } or - * {@link #getDate getDate } are permitted - * without re-establishing a connection. That is because UDP is a - * connectionless protocol and the Time protocol is stateless. - *

- *

- * @author Daniel F. Savarese - * @see TimeTCPClient - ***/ - -public final class TimeUDPClient extends DatagramSocketClient -{ - /*** The default time port. It is set to 37 according to RFC 868. ***/ - public static final int DEFAULT_PORT = 37; - - /*** - * The number of seconds between 00:00 1 January 1900 and - * 00:00 1 January 1970. This value can be useful for converting - * time values to other formats. - ***/ - public static final long SECONDS_1900_TO_1970 = 2208988800L; - - private byte[] __dummyData = new byte[1]; - private byte[] __timeData = new byte[4]; - - /*** - * Retrieves the time from the specified server and port and - * returns it. The time is the number of seconds since - * 00:00 (midnight) 1 January 1900 GMT, as specified by RFC 868. - * This method reads the raw 32-bit big-endian - * unsigned integer from the server, converts it to a Java long, and - * returns the value. - *

- * @param host The address of the server. - * @param port The port of the service. - * @return The time value retrieved from the server. - * @exception IOException If an error occurs while retrieving the time. - ***/ - public long getTime(InetAddress host, int port) throws IOException - { - long time; - DatagramPacket sendPacket, receivePacket; - - sendPacket = - new DatagramPacket(__dummyData, __dummyData.length, host, port); - receivePacket = new DatagramPacket(__timeData, __timeData.length); - - _socket_.send(sendPacket); - _socket_.receive(receivePacket); - - time = 0L; - time |= (((__timeData[0] & 0xff) << 24) & 0xffffffffL); - time |= (((__timeData[1] & 0xff) << 16) & 0xffffffffL); - time |= (((__timeData[2] & 0xff) << 8) & 0xffffffffL); - time |= ((__timeData[3] & 0xff) & 0xffffffffL); - - return time; - } - - /*** Same as getTime(host, DEFAULT_PORT); ***/ - public long getTime(InetAddress host) throws IOException - { - return getTime(host, DEFAULT_PORT); - } - - - /*** - * Retrieves the time from the server and returns a Java Date - * containing the time converted to the local timezone. - *

- * @param host The address of the server. - * @param port The port of the service. - * @return A Date value containing the time retrieved from the server - * converted to the local timezone. - * @exception IOException If an error occurs while fetching the time. - ***/ - public Date getDate(InetAddress host, int port) throws IOException - { - return new Date((getTime(host, port) - SECONDS_1900_TO_1970)*1000L); - } - - - /*** Same as getTime(host, DEFAULT_PORT); ***/ - public Date getDate(InetAddress host) throws IOException - { - return new Date((getTime(host, DEFAULT_PORT) - - SECONDS_1900_TO_1970)*1000L); - } - -} - diff --git a/org/apache/commons/net/util/ListenerList.class b/org/apache/commons/net/util/ListenerList.class deleted file mode 100644 index f05ebb5..0000000 Binary files a/org/apache/commons/net/util/ListenerList.class and /dev/null differ diff --git a/org/apache/commons/net/util/ListenerList.java b/org/apache/commons/net/util/ListenerList.java deleted file mode 100644 index 796fb78..0000000 --- a/org/apache/commons/net/util/ListenerList.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.util; - -import java.io.Serializable; -import java.util.EventListener; -import java.util.Iterator; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * @author Daniel F. Savarese - */ - -public class ListenerList implements Serializable, Iterable -{ - private final CopyOnWriteArrayList __listeners; - - public ListenerList() - { - __listeners = new CopyOnWriteArrayList(); - } - - public void addListener(EventListener listener) - { - __listeners.add(listener); - } - - public void removeListener(EventListener listener) - { - __listeners.remove(listener); - } - - public int getListenerCount() - { - return __listeners.size(); - } - - /** - * Return an {@link Iterator} for the {@link EventListener} instances - * - * @since 2.0 - * TODO Check that this is a good defensive strategy - */ - public Iterator iterator() { - return __listeners.iterator(); - } - -} diff --git a/org/apache/commons/net/util/SubnetUtils.java b/org/apache/commons/net/util/SubnetUtils.java deleted file mode 100644 index 90cc6e8..0000000 --- a/org/apache/commons/net/util/SubnetUtils.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.net.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A class that performs some subnet calculations given a network address and a subnet mask. - * @see http://www.faqs.org/rfcs/rfc1519.html - * @author - * @since 2.0 - */ -public class SubnetUtils { - - private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"; - private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,3})"; - private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS); - private static final Pattern cidrPattern = Pattern.compile(SLASH_FORMAT); - private static final int NBITS = 32; - - private int netmask = 0; - private int address = 0; - private int network = 0; - private int broadcast = 0; - - /** - * Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" - * @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16" - */ - public SubnetUtils(String cidrNotation) { - calculate(cidrNotation); - } - - /** - * Constructor that takes two dotted decimal addresses. - * @param address An IP address, e.g. "192.168.0.1" - * @param mask A dotted decimal netmask e.g. "255.255.0.0" - */ - public SubnetUtils(String address, String mask) { - calculate(toCidrNotation(address, mask)); - } - - /** - * Convenience container for subnet summary information. - * - */ - public final class SubnetInfo { - private SubnetInfo() {} - - private int netmask() { return netmask; } - private int network() { return network; } - private int address() { return address; } - private int broadcast() { return broadcast; } - private int low() { return network() + 1; } - private int high() { return broadcast() - 1; } - - public boolean isInRange(String address) { return isInRange(toInteger(address)); } - private boolean isInRange(int address) { return ((address-low()) <= (high()-low())); } - - public String getBroadcastAddress() { return format(toArray(broadcast())); } - public String getNetworkAddress() { return format(toArray(network())); } - public String getNetmask() { return format(toArray(netmask())); } - public String getAddress() { return format(toArray(address())); } - public String getLowAddress() { return format(toArray(low())); } - public String getHighAddress() { return format(toArray(high())); } - public int getAddressCount() { return (broadcast() - low()); } - - public int asInteger(String address) { return toInteger(address); } - - public String getCidrSignature() { - return toCidrNotation( - format(toArray(address())), - format(toArray(netmask())) - ); - } - - public String[] getAllAddresses() { - String[] addresses = new String[getAddressCount()]; - for (int add = low(), j=0; add <= high(); ++add, ++j) { - addresses[j] = format(toArray(add)); - } - return addresses; - } - } - - /** - * Return a {@link SubnetInfo} instance that contains subnet-specific statistics - * @return - */ - public final SubnetInfo getInfo() { return new SubnetInfo(); } - - /* - * Initialize the internal fields from the supplied CIDR mask - */ - private void calculate(String mask) { - Matcher matcher = cidrPattern.matcher(mask); - - if (matcher.matches()) { - address = matchAddress(matcher); - - /* Create a binary netmask from the number of bits specification /x */ - int cidrPart = rangeCheck(Integer.parseInt(matcher.group(5)), 0, NBITS-1); - for (int j = 0; j < cidrPart; ++j) { - netmask |= (1 << 31-j); - } - - /* Calculate base network address */ - network = (address & netmask); - - /* Calculate broadcast address */ - broadcast = network | ~(netmask); - } - else - throw new IllegalArgumentException("Could not parse [" + mask + "]"); - } - - /* - * Convert a dotted decimal format address to a packed integer format - */ - private int toInteger(String address) { - Matcher matcher = addressPattern.matcher(address); - if (matcher.matches()) { - return matchAddress(matcher); - } - else - throw new IllegalArgumentException("Could not parse [" + address + "]"); - } - - /* - * Convenience method to extract the components of a dotted decimal address and - * pack into an integer using a regex match - */ - private int matchAddress(Matcher matcher) { - int addr = 0; - for (int i = 1; i <= 4; ++i) { - int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255)); - addr |= ((n & 0xff) << 8*(4-i)); - } - return addr; - } - - /* - * Convert a packed integer address into a 4-element array - */ - private int[] toArray(int val) { - int ret[] = new int[4]; - for (int j = 3; j >= 0; --j) - ret[j] |= ((val >>> 8*(3-j)) & (0xff)); - return ret; - } - - /* - * Convert a 4-element array into dotted decimal format - */ - private String format(int[] octets) { - StringBuilder str = new StringBuilder(); - for (int i =0; i < octets.length; ++i){ - str.append(octets[i]); - if (i != octets.length - 1) { - str.append("."); - } - } - return str.toString(); - } - - /* - * Convenience function to check integer boundaries - */ - private int rangeCheck(int value, int begin, int end) { - if (value >= begin && value <= end) - return value; - - throw new IllegalArgumentException("Value out of range: [" + value + "]"); - } - - /* - * Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy - * see Hacker's Delight section 5.1 - */ - int pop(int x) { - x = x - ((x >>> 1) & 0x55555555); - x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); - x = (x + (x >>> 4)) & 0x0F0F0F0F; - x = x + (x >>> 8); - x = x + (x >>> 16); - return x & 0x0000003F; - } - - /* Convert two dotted decimal addresses to a single xxx.xxx.xxx.xxx/yy format - * by counting the 1-bit population in the mask address. (It may be better to count - * NBITS-#trailing zeroes for this case) - */ - private String toCidrNotation(String addr, String mask) { - return addr + "/" + pop(toInteger(mask)); - } -} diff --git a/org/apache/commons/net/whois/WhoisClient.java b/org/apache/commons/net/whois/WhoisClient.java deleted file mode 100644 index 74cc064..0000000 --- a/org/apache/commons/net/whois/WhoisClient.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.whois; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.net.finger.FingerClient; - -/*** - * The WhoisClient class implements the client side of the Internet Whois - * Protocol defined in RFC 954. To query a host you create a - * WhoisClient instance, connect to the host, query the host, and finally - * disconnect from the host. If the whois service you want to query is on - * a non-standard port, connect to the host at that port. - * Here's a sample use: - *

- *    WhoisClient whois;
- *
- *    whois = new WhoisClient();
- *
- *    try {
- *      whois.connect(WhoisClient.DEFAULT_HOST);
- *      System.out.println(whois.query("foobar"));
- *      whois.disconnect();
- *    } catch(IOException e) {
- *      System.err.println("Error I/O exception: " + e.getMessage());
- *      return;
- *    }
- * 
- * - *

- *

- * @author Daniel F. Savarese - ***/ - -public final class WhoisClient extends FingerClient -{ - /*** - * The default whois host to query. It is set to whois.internic.net. - ***/ - public static final String DEFAULT_HOST = "whois.internic.net"; - - /*** - * The default whois port. It is set to 43 according to RFC 954. - ***/ - public static final int DEFAULT_PORT = 43; - - - /*** - * The default whois constructor. Initializes the - * default port to DEFAULT_PORT . - ***/ - public WhoisClient() - { - setDefaultPort(DEFAULT_PORT); - } - - /*** - * Queries the connected whois server for information regarding - * the given handle. It is up to the programmer to be familiar with the - * handle syntax of the whois server. You must first connect to a whois - * server before calling this method, and you should disconnect afterward. - *

- * @param handle The handle to lookup. - * @return The result of the whois query. - * @exception IOException If an I/O error occurs during the operation. - ***/ - public String query(String handle) throws IOException - { - return query(false, handle); - } - - - /*** - * Queries the connected whois server for information regarding - * the given handle and returns the InputStream of the network connection. - * It is up to the programmer to be familiar with the handle syntax - * of the whois server. You must first connect to a finger server before - * calling this method, and you should disconnect after finishing reading - * the stream. - *

- * @param handle The handle to lookup. - * @return The InputStream of the network connection of the whois query. - * Can be read to obtain whois results. - * @exception IOException If an I/O error occurs during the operation. - ***/ - public InputStream getInputStream(String handle) throws IOException - { - return getInputStream(false, handle); - } - -} - -- cgit v1.2.3