| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.ArrayList; |
| import java.util.List; |
| |
| import org.apache.commons.net.MalformedServerReplyException; |
| import org.apache.commons.net.ProtocolCommandSupport; |
| import org.apache.commons.net.SocketClient; |
| import org.apache.commons.net.io.CRLFLineReader; |
| |
| /*** |
| * 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}. |
| * <p> |
| * 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. |
| * |
| * |
| * @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"; |
| // The reply indicating intermediate response to a command. |
| static final String _OK_INT = "+ "; |
| 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. |
| static final String _DEFAULT_ENCODING = "ISO-8859-1"; |
| |
| private int __popState; |
| BufferedWriter _writer; |
| |
| BufferedReader _reader; |
| int _replyCode; |
| String _lastReplyLine; |
| List<String> _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 <code>DISCONNECTED_STATE</code>. |
| ***/ |
| public POP3() |
| { |
| setDefaultPort(DEFAULT_PORT); |
| __popState = DISCONNECTED_STATE; |
| _reader = null; |
| _writer = null; |
| _replyLines = new ArrayList<String>(); |
| _commandSupport_ = new ProtocolCommandSupport(this); |
| } |
| |
| private void __getReply() throws IOException |
| { |
| String line; |
| |
| _replyLines.clear(); |
| 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 if (line.startsWith(_OK_INT)) { |
| _replyCode = POP3Reply.OK_INT; |
| } else { |
| throw new |
| MalformedServerReplyException( |
| "Received invalid POP3 protocol response from server." + line); |
| } |
| |
| _replyLines.add(line); |
| _lastReplyLine = line; |
| |
| fireReplyReceived(_replyCode, getReplyString()); |
| } |
| |
| |
| /*** |
| * Performs connection initialization and sets state to |
| * <code> AUTHORIZATION_STATE </code>. |
| ***/ |
| @Override |
| protected void _connectAction_() throws IOException |
| { |
| super._connectAction_(); |
| _reader = |
| new CRLFLineReader(new InputStreamReader(_input_, |
| _DEFAULT_ENCODING)); |
| _writer = |
| new BufferedWriter(new OutputStreamWriter(_output_, |
| _DEFAULT_ENCODING)); |
| __getReply(); |
| setState(AUTHORIZATION_STATE); |
| } |
| |
| |
| /** |
| * Set the internal POP3 state. |
| * @param state the new state. This must be one of the <code>_STATE</code> constants. |
| */ |
| 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. |
| * @throws IOException on error |
| ***/ |
| public void getAdditionalReply() throws IOException |
| { |
| String line; |
| |
| line = _reader.readLine(); |
| while (line != null) |
| { |
| _replyLines.add(line); |
| if (line.equals(".")) { |
| break; |
| } |
| line = _reader.readLine(); |
| } |
| } |
| |
| |
| /*** |
| * Disconnects the client from the server, and sets the state to |
| * <code> DISCONNECTED_STATE </code>. The reply text information |
| * from the last issued command is voided to allow garbage collection |
| * of the memory used to store that information. |
| * |
| * @throws IOException If there is an error in disconnecting. |
| ***/ |
| @Override |
| public void disconnect() throws IOException |
| { |
| super.disconnect(); |
| _reader = null; |
| _writer = null; |
| _lastReplyLine = null; |
| _replyLines.clear(); |
| 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, POP3Reply.ERROR or POP3Reply.OK_INT). |
| * @throws IOException on error |
| ***/ |
| public int sendCommand(String command, String args) throws IOException |
| { |
| if (_writer == null) { |
| throw new IllegalStateException("Socket is not connected"); |
| } |
| StringBuilder __commandBuffer = new StringBuilder(); |
| __commandBuffer.append(command); |
| |
| if (args != null) |
| { |
| __commandBuffer.append(' '); |
| __commandBuffer.append(args); |
| } |
| __commandBuffer.append(SocketClient.NETASCII_EOL); |
| |
| String message = __commandBuffer.toString(); |
| _writer.write(message); |
| _writer.flush(); |
| |
| 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, POP3Reply.ERROR or POP3Reply.OK_INT). |
| * @throws IOException on 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, POP3Reply.ERROR or POP3Reply.OK_INT). |
| * @throws IOException on 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, POP3Reply.ERROR or POP3Reply.OK_INT). |
| * @throws IOException on 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 <code>getReplyStrings</code> |
| * 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() |
| { |
| return _replyLines.toArray(new String[_replyLines.size()]); |
| } |
| |
| /*** |
| * 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 <code>getReplyString</code> |
| * 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() |
| { |
| StringBuilder buffer = new StringBuilder(256); |
| |
| for (String entry : _replyLines) |
| { |
| buffer.append(entry); |
| buffer.append(SocketClient.NETASCII_EOL); |
| } |
| |
| return buffer.toString(); |
| } |
| |
| /** |
| * Removes a ProtocolCommandListener. |
| * |
| * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to |
| * the correct method {@link SocketClient#removeProtocolCommandListener} |
| * @param listener The ProtocolCommandListener to remove |
| */ |
| public void removeProtocolCommandistener(org.apache.commons.net.ProtocolCommandListener listener){ |
| removeProtocolCommandListener(listener); |
| } |
| |
| /** |
| * Provide command support to super-class |
| */ |
| @Override |
| protected ProtocolCommandSupport getCommandSupport() { |
| return _commandSupport_; |
| } |
| } |
| |