View Javadoc

    1   /*
    2    * Copyright 2001-2005 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.net.pop3;
    17
    18  import java.io.BufferedReader;
    19  import java.io.BufferedWriter;
    20  import java.io.EOFException;
    21  import java.io.IOException;
    22  import java.io.InputStreamReader;
    23  import java.io.OutputStreamWriter;
    24  import java.lang.StringBuffer;
    25  import java.util.Enumeration;
    26  import java.util.Vector;
    27  import org.apache.commons.net.MalformedServerReplyException;
    28  import org.apache.commons.net.ProtocolCommandListener;
    29  import org.apache.commons.net.ProtocolCommandSupport;
    30  import org.apache.commons.net.SocketClient;
    31
    32  /****
    33   * The POP3 class is not meant to be used by itself and is provided
    34   * only so that you may easily implement your own POP3 client if
    35   * you so desire.  If you have no need to perform your own implementation,
    36   * you should use {@link org.apache.commons.net.pop3.POP3Client}.
    37   * <p>
    38   * Rather than list it separately for each method, we mention here that
    39   * every method communicating with the server and throwing an IOException
    40   * can also throw a
    41   * {@link org.apache.commons.net.MalformedServerReplyException}
    42   * , which is a subclass
    43   * of IOException.  A MalformedServerReplyException will be thrown when
    44   * the reply received from the server deviates enough from the protocol
    45   * specification that it cannot be interpreted in a useful manner despite
    46   * attempts to be as lenient as possible.
    47   * <p>
    48   * <p>
    49   * @author Daniel F. Savarese
    50   * @see POP3Client
    51   * @see org.apache.commons.net.MalformedServerReplyException
    52   ***/
    53
    54  public class POP3 extends SocketClient
    55  {
    56      /**** The default POP3 port.  Set to 110 according to RFC 1288. ***/
    57      public static final int DEFAULT_PORT = 110;
    58      /****
    59       * A constant representing the state where the client is not yet connected
    60       * to a POP3 server.
    61       ***/
    62      public static final int DISCONNECTED_STATE = -1;
    63      /****  A constant representing the POP3 authorization state. ***/
    64      public static final int AUTHORIZATION_STATE = 0;
    65      /****  A constant representing the POP3 transaction state. ***/
    66      public static final int TRANSACTION_STATE = 1;
    67      /****  A constant representing the POP3 update state. ***/
    68      public static final int UPDATE_STATE = 2;
    69
    70      static final String _OK = "+OK";
    71      static final String _ERROR = "-ERR";
    72
    73      // We have to ensure that the protocol communication is in ASCII
    74      // but we use ISO-8859-1 just in case 8-bit characters cross
    75      // the wire.
    76      private static final String __DEFAULT_ENCODING = "ISO-8859-1";
    77
    78      private int __popState;
    79      private BufferedWriter __writer;
    80      private StringBuffer __commandBuffer;
    81
    82      BufferedReader _reader;
    83      int _replyCode;
    84      String _lastReplyLine;
    85      Vector _replyLines;
    86
    87      /****
    88       * A ProtocolCommandSupport object used to manage the registering of
    89       * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
    90       ***/
    91      protected ProtocolCommandSupport _commandSupport_;
    92
    93      /****
    94       * The default POP3Client constructor.  Initializes the state
    95       * to <code>DISCONNECTED_STATE</code>.
    96       ***/
    97      public POP3()
    98      {
    99          setDefaultPort(DEFAULT_PORT);
    100         __commandBuffer = new StringBuffer();
    101         __popState = DISCONNECTED_STATE;
    102         _reader = null;
    103         __writer = null;
    104         _replyLines = new Vector();
    105         _commandSupport_ = new ProtocolCommandSupport(this);
    106     }
    107
    108     private void __getReply() throws IOException
    109     {
    110         String line;
    111
    112         _replyLines.setSize(0);
    113         line = _reader.readLine();
    114
    115         if (line == null)
    116             throw new EOFException("Connection closed without indication.");
    117
    118         if (line.startsWith(_OK))
    119             _replyCode = POP3Reply.OK;
    120         else if (line.startsWith(_ERROR))
    121             _replyCode = POP3Reply.ERROR;
    122         else
    123             throw new
    124             MalformedServerReplyException(
    125                 "Received invalid POP3 protocol response from server.");
    126
    127         _replyLines.addElement(line);
    128         _lastReplyLine = line;
    129
    130         if (_commandSupport_.getListenerCount() > 0)
    131             _commandSupport_.fireReplyReceived(_replyCode, getReplyString());
    132     }
    133
    134
    135     /****
    136      * Performs connection initialization and sets state to
    137      * <code> AUTHORIZATION_STATE </code>.
    138      ***/
    139     protected void _connectAction_() throws IOException
    140     {
    141         super._connectAction_();
    142         _reader =
    143           new BufferedReader(new InputStreamReader(_input_,
    144                                                    __DEFAULT_ENCODING));
    145         __writer =
    146           new BufferedWriter(new OutputStreamWriter(_output_,
    147                                                     __DEFAULT_ENCODING));
    148         __getReply();
    149         setState(AUTHORIZATION_STATE);
    150     }
    151
    152
    153     /****
    154      * Adds a ProtocolCommandListener.  Delegates this task to
    155      * {@link #_commandSupport_  _commandSupport_ }.
    156      * <p>
    157      * @param listener  The ProtocolCommandListener to add.
    158      ***/
    159     public void addProtocolCommandListener(ProtocolCommandListener listener)
    160     {
    161         _commandSupport_.addProtocolCommandListener(listener);
    162     }
    163
    164     /****
    165      * Removes a ProtocolCommandListener.  Delegates this task to
    166      * {@link #_commandSupport_  _commandSupport_ }.
    167      * <p>
    168      * @param listener  The ProtocolCommandListener to remove.
    169      ***/
    170     public void removeProtocolCommandistener(ProtocolCommandListener listener)
    171     {
    172         _commandSupport_.removeProtocolCommandListener(listener);
    173     }
    174
    175
    176     /****
    177      * Sets POP3 client state.  This must be one of the
    178      * <code>_STATE</code> constants.
    179      * <p>
    180      * @param state  The new state.
    181      ***/
    182     public void setState(int state)
    183     {
    184         __popState = state;
    185     }
    186
    187
    188     /****
    189      * Returns the current POP3 client state.
    190      * <p>
    191      * @return The current POP3 client state.
    192      ***/
    193     public int getState()
    194     {
    195         return __popState;
    196     }
    197
    198
    199     /****
    200      * Retrieves the additional lines of a multi-line server reply.
    201      ***/
    202     public void getAdditionalReply() throws IOException
    203     {
    204         String line;
    205
    206         line = _reader.readLine();
    207         while (line != null)
    208         {
    209             _replyLines.addElement(line);
    210             if (line.equals("."))
    211                 break;
    212             line = _reader.readLine();
    213         }
    214     }
    215
    216
    217     /****
    218      * Disconnects the client from the server, and sets the state to
    219      * <code> DISCONNECTED_STATE </code>.  The reply text information
    220      * from the last issued command is voided to allow garbage collection
    221      * of the memory used to store that information.
    222      * <p>
    223      * @exception IOException  If there is an error in disconnecting.
    224      ***/
    225     public void disconnect() throws IOException
    226     {
    227         super.disconnect();
    228         _reader = null;
    229         __writer = null;
    230         _lastReplyLine = null;
    231         _replyLines.setSize(0);
    232         setState(DISCONNECTED_STATE);
    233     }
    234
    235
    236     /****
    237      * Sends a command an arguments to the server and returns the reply code.
    238      * <p>
    239      * @param command  The POP3 command to send.
    240      * @param args     The command arguments.
    241      * @return  The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
    242      ***/
    243     public int sendCommand(String command, String args) throws IOException
    244     {
    245         String message;
    246
    247         __commandBuffer.setLength(0);
    248         __commandBuffer.append(command);
    249
    250         if (args != null)
    251         {
    252             __commandBuffer.append(' ');
    253             __commandBuffer.append(args);
    254         }
    255         __commandBuffer.append(SocketClient.NETASCII_EOL);
    256
    257         __writer.write(message = __commandBuffer.toString());
    258         __writer.flush();
    259
    260         if (_commandSupport_.getListenerCount() > 0)
    261             _commandSupport_.fireCommandSent(command, message);
    262
    263         __getReply();
    264         return _replyCode;
    265     }
    266
    267     /****
    268      * Sends a command with no arguments to the server and returns the
    269      * reply code.
    270      * <p>
    271      * @param command  The POP3 command to send.
    272      * @return  The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
    273      ***/
    274     public int sendCommand(String command) throws IOException
    275     {
    276         return sendCommand(command, null);
    277     }
    278
    279     /****
    280      * Sends a command an arguments to the server and returns the reply code.
    281      * <p>
    282      * @param command  The POP3 command to send
    283      *                  (one of the POP3Command constants).
    284      * @param args     The command arguments.
    285      * @return  The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
    286      ***/
    287     public int sendCommand(int command, String args) throws IOException
    288     {
    289         return sendCommand(POP3Command._commands[command], args);
    290     }
    291
    292     /****
    293      * Sends a command with no arguments to the server and returns the
    294      * reply code.
    295      * <p>
    296      * @param command  The POP3 command to send
    297      *                  (one of the POP3Command constants).
    298      * @return  The server reply code (either POP3Reply.OK or POP3Reply.ERROR).
    299      ***/
    300     public int sendCommand(int command) throws IOException
    301     {
    302         return sendCommand(POP3Command._commands[command], null);
    303     }
    304
    305
    306     /****
    307      * Returns an array of lines received as a reply to the last command
    308      * sent to the server.  The lines have end of lines truncated.  If
    309      * the reply is a single line, but its format ndicates it should be
    310      * a multiline reply, then you must call
    311      * {@link #getAdditionalReply  getAdditionalReply() } to
    312      * fetch the rest of the reply, and then call <code>getReplyStrings</code>
    313      * again.  You only have to worry about this if you are implementing
    314      * your own client using the {@link #sendCommand  sendCommand } methods.
    315      * <p>
    316      * @return The last server response.
    317      ***/
    318     public String[] getReplyStrings()
    319     {
    320         String[] lines;
    321         lines = new String[_replyLines.size()];
    322         _replyLines.copyInto(lines);
    323         return lines;
    324     }
    325
    326     /****
    327      * Returns the reply to the last command sent to the server.
    328      * The value is a single string containing all the reply lines including
    329      * newlines.  If the reply is a single line, but its format ndicates it
    330      * should be a multiline reply, then you must call
    331      * {@link #getAdditionalReply  getAdditionalReply() } to
    332      * fetch the rest of the reply, and then call <code>getReplyString</code>
    333      * again.  You only have to worry about this if you are implementing
    334      * your own client using the {@link #sendCommand  sendCommand } methods.
    335      * <p>
    336      * @return The last server response.
    337      ***/
    338     public String getReplyString()
    339     {
    340         Enumeration en;
    341         StringBuffer buffer = new StringBuffer(256);
    342
    343         en = _replyLines.elements();
    344         while (en.hasMoreElements())
    345         {
    346             buffer.append((String)en.nextElement());
    347             buffer.append(SocketClient.NETASCII_EOL);
    348         }
    349
    350         return buffer.toString();
    351     }
    352
    353 }
    354