    View Javadoc
    1   package org.apache.commons.net.pop3;
    2
    3   /* ====================================================================
    4    * The Apache Software License, Version 1.1
    5    *
    6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
    7    * reserved.
    8    *
    9    * Redistribution and use in source and binary forms, with or without
    10   * modification, are permitted provided that the following conditions
    11   * are met:
    12   *
    13   * 1. Redistributions of source code must retain the above copyright
    14   *    notice, this list of conditions and the following disclaimer.
    15   *
    16   * 2. Redistributions in binary form must reproduce the above copyright
    17   *    notice, this list of conditions and the following disclaimer in
    18   *    the documentation and/or other materials provided with the
    19   *    distribution.
    20   *
    21   * 3. The end-user documentation included with the redistribution,
    22   *    if any, must include the following acknowledgment:
    23   *       "This product includes software developed by the
    24   *        Apache Software Foundation (http://www.apache.org/)."
    25   *    Alternately, this acknowledgment may appear in the software itself,
    26   *    if and wherever such third-party acknowledgments normally appear.
    27   *
    28   * 4. The names "Apache" and "Apache Software Foundation" and
    29   *    "Apache Commons" must not be used to endorse or promote products
    30   *    derived from this software without prior written permission. For
    31   *    written permission, please contact apache@apache.org.
    32   *
    33   * 5. Products derived from this software may not be called "Apache",
    34   *    nor may "Apache" appear in their name, without
    35   *    prior written permission of the Apache Software Foundation.
    36   *
    37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
    41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    48   * SUCH DAMAGE.
    49   * ====================================================================
    50   *
    51   * This software consists of voluntary contributions made by many
    52   * individuals on behalf of the Apache Software Foundation.  For more
    53   * information on the Apache Software Foundation, please see
    54   * <http://www.apache.org/>;.
    55   */
    56
    57  import java.io.IOException;
    58  import java.io.Reader;
    59  import java.security.MessageDigest;
    60  import java.security.NoSuchAlgorithmException;
    61  import java.util.Enumeration;
    62  import java.util.StringTokenizer;
    63  import org.apache.commons.net.io.DotTerminatedMessageReader;
    64
    65  /****
    66   * The POP3Client class implements the client side of the Internet POP3
    67   * Protocol defined in RFC 1939.  All commands are supported, including
    68   * the APOP command which requires MD5 encryption.  See RFC 1939 for
    69   * more details on the POP3 protocol.
    70   * <p>
    71   * Rather than list it separately for each method, we mention here that
    72   * every method communicating with the server and throwing an IOException
    73   * can also throw a
    74   * <a href="org.apache.commons.net.MalformedServerReplyException.html">
    75   * MalformedServerReplyException </a>, which is a subclass
    76   * of IOException.  A MalformedServerReplyException will be thrown when
    77   * the reply received from the server deviates enough from the protocol
    78   * specification that it cannot be interpreted in a useful manner despite
    79   * attempts to be as lenient as possible.
    80   * <p>
    81   * <p>
    82   * @author Daniel F. Savarese
    83   * @see POP3MessageInfo
    84   * @see org.apache.commons.net.io.DotTerminatedMessageReader
    85   * @see org.apache.commons.net.MalformedServerReplyException
    86   ***/
    87
    88  public class POP3Client extends POP3
    89  {
    90
    91      private static POP3MessageInfo __parseStatus(String line)
    92      {
    93          int num, size;
    94          StringTokenizer tokenizer;
    95
    96          tokenizer = new StringTokenizer(line);
    97
    98          if (!tokenizer.hasMoreElements())
    99              return null;
    100
    101         num = size = 0;
    102
    103         try
    104         {
    105             num = Integer.parseInt(tokenizer.nextToken());
    106
    107             if (!tokenizer.hasMoreElements())
    108                 return null;
    109
    110             size = Integer.parseInt(tokenizer.nextToken());
    111         }
    112         catch (NumberFormatException e)
    113         {
    114             return null;
    115         }
    116
    117         return new POP3MessageInfo(num, size);
    118     }
    119
    120     private static POP3MessageInfo __parseUID(String line)
    121     {
    122         int num;
    123         StringTokenizer tokenizer;
    124
    125         tokenizer = new StringTokenizer(line);
    126
    127         if (!tokenizer.hasMoreElements())
    128             return null;
    129
    130         num = 0;
    131
    132         try
    133         {
    134             num = Integer.parseInt(tokenizer.nextToken());
    135
    136             if (!tokenizer.hasMoreElements())
    137                 return null;
    138
    139             line = tokenizer.nextToken();
    140         }
    141         catch (NumberFormatException e)
    142         {
    143             return null;
    144         }
    145
    146         return new POP3MessageInfo(num, line);
    147     }
    148
    149     /****
    150      * Login to the POP3 server with the given username and password.  You
    151      * must first connect to the server with
    152      * <a href="org.apache.commons.net.SocketClient.html#connect"> connect </a>
    153      * before attempting to login.  A login attempt is only valid if
    154      * the client is in the
    155      * <a href="org.apache.commons.net.pop3.POP3.html#AUTHORIZATION_STATE">
    156      * AUTHORIZATION_STATE </a>.  After logging in, the client enters the
    157      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    158      * TRANSACTION_STATE </a>.
    159      * <p>
    160      * @param username  The account name being logged in to.
    161      * @param password  The plain text password of the account.
    162      * @return True if the login attempt was successful, false if not.
    163      * @exception IOException If a network I/O error occurs in the process of
    164      *            logging in.
    165      ***/
    166     public boolean login(String username, String password) throws IOException
    167     {
    168         if (getState() != AUTHORIZATION_STATE)
    169             return false;
    170
    171         if (sendCommand(POP3Command.USER, username) != POP3Reply.OK)
    172             return false;
    173
    174         if (sendCommand(POP3Command.PASS, password) != POP3Reply.OK)
    175             return false;
    176
    177         setState(TRANSACTION_STATE);
    178
    179         return true;
    180     }
    181
    182
    183     /****
    184      * Login to the POP3 server with the given username and authentication
    185      * information.  Use this method when connecting to a server requiring
    186      * authentication using the APOP command.  Because the timestamp
    187      * produced in the greeting banner varies from server to server, it is
    188      * not possible to consistently extract the information.  Therefore,
    189      * after connecting to the server, you must call
    190      * <a href="org.apache.commons.net.pop3.POP3.html#getReplyString">
    191      * getReplyString </a> and parse out the timestamp information yourself.
    192      * <p>
    193      * You must first connect to the server with
    194      * <a href="org.apache.commons.net.SocketClient.html#connect"> connect </a>
    195      * before attempting to login.  A login attempt is only valid if
    196      * the client is in the
    197      * <a href="org.apache.commons.net.pop3.POP3.html#AUTHORIZATION_STATE">
    198      * AUTHORIZATION_STATE </a>.  After logging in, the client enters the
    199      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    200      * TRANSACTION_STATE </a>.  After connecting, you must parse out the
    201      * server specific information to use as a timestamp, and pass that
    202      * information to this method.  The secret is a shared secret known
    203      * to you and the server.  See RFC 1939 for more details regarding
    204      * the APOP command.
    205      * <p>
    206      * @param username  The account name being logged in to.
    207      * @param timestamp  The timestamp string to combine with the secret.
    208      * @param secret  The shared secret which produces the MD5 digest when
    209      *        combined with the timestamp.
    210      * @return True if the login attempt was successful, false if not.
    211      * @exception IOException If a network I/O error occurs in the process of
    212      *            logging in.
    213      * @exception NoSuchAlgorithmException If the MD5 encryption algorithm
    214      *      cannot be instantiated by the Java runtime system.
    215      ***/
    216     public boolean login(String username, String timestamp, String secret)
    217     throws IOException, NoSuchAlgorithmException
    218     {
    219         int i;
    220         byte[] digest;
    221         StringBuffer buffer, digestBuffer;
    222         MessageDigest md5;
    223
    224         if (getState() != AUTHORIZATION_STATE)
    225             return false;
    226
    227         md5 = MessageDigest.getInstance("MD5");
    228         timestamp += secret;
    229         digest = md5.digest(timestamp.getBytes());
    230         digestBuffer = new StringBuffer(128);
    231
    232         for (i = 0; i < digest.length; i++)
    233             digestBuffer.append(Integer.toHexString(digest[i] & 0xff));
    234
    235         buffer = new StringBuffer(256);
    236         buffer.append(username);
    237         buffer.append(' ');
    238         buffer.append(digestBuffer.toString());
    239
    240         if (sendCommand(POP3Command.APOP, buffer.toString()) != POP3Reply.OK)
    241             return false;
    242
    243         setState(TRANSACTION_STATE);
    244
    245         return true;
    246     }
    247
    248
    249     /****
    250      * Logout of the POP3 server.  To fully disconnect from the server
    251      * you must call
    252      * <a href="org.apache.commons.net.pop3.POP3.html#disconnect"> disconnect </a>.
    253      * A logout attempt is valid in any state.  If
    254      * the client is in the
    255      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    256      * TRANSACTION_STATE </a>, it enters the
    257      * <a href="org.apache.commons.net.pop3.POP3.html#UPDATE_STATE">
    258      * UPDATE_STATE </a> on a successful logout.
    259      * <p>
    260      * @return True if the logout attempt was successful, false if not.
    261      * @exception IOException If a network I/O error occurs in the process
    262      *           of logging out.
    263      ***/
    264     public boolean logout() throws IOException
    265     {
    266         if (getState() == TRANSACTION_STATE)
    267             setState(UPDATE_STATE);
    268         sendCommand(POP3Command.QUIT);
    269         return (_replyCode == POP3Reply.OK);
    270     }
    271
    272
    273     /****
    274      * Send a NOOP command to the POP3 server.  This is useful for keeping
    275      * a connection alive since most POP3 servers will timeout after 10
    276      * minutes of inactivity.  A noop attempt will only succeed if
    277      * the client is in the
    278      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    279      * TRANSACTION_STATE </a>.
    280      * <p>
    281      * @return True if the noop attempt was successful, false if not.
    282      * @exception IOException If a network I/O error occurs in the process of
    283      *        sending the NOOP command.
    284      ***/
    285     public boolean noop() throws IOException
    286     {
    287         if (getState() == TRANSACTION_STATE)
    288             return (sendCommand(POP3Command.NOOP) == POP3Reply.OK);
    289         return false;
    290     }
    291
    292
    293     /****
    294      * Delete a message from the POP3 server.  The message is only marked
    295      * for deletion by the server.  If you decide to unmark the message, you
    296      * must issuse a <a href="#reset"> reset </a> command.  Messages marked
    297      * for deletion are only deleted by the server on
    298      * <a href="#logout"> logout </a>.
    299      * A delete attempt can only succeed if the client is in the
    300      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    301      * TRANSACTION_STATE </a>.
    302      * <p>
    303      * @param messageId  The message number to delete.
    304      * @return True if the deletion attempt was successful, false if not.
    305      * @exception IOException If a network I/O error occurs in the process of
    306      *           sending the delete command.
    307      ***/
    308     public boolean deleteMessage(int messageId) throws IOException
    309     {
    310         if (getState() == TRANSACTION_STATE)
    311             return (sendCommand(POP3Command.DELE, Integer.toString(messageId))
    312                     == POP3Reply.OK);
    313         return false;
    314     }
    315
    316
    317     /****
    318      * Reset the POP3 session.  This is useful for undoing any message
    319      * deletions that may have been performed.  A reset attempt can only
    320      * succeed if the client is in the
    321      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    322      * TRANSACTION_STATE </a>.
    323      * <p>
    324      * @return True if the reset attempt was successful, false if not.
    325      * @exception IOException If a network I/O error occurs in the process of
    326      *      sending the reset command.
    327      ***/
    328     public boolean reset() throws IOException
    329     {
    330         if (getState() == TRANSACTION_STATE)
    331             return (sendCommand(POP3Command.RSET) == POP3Reply.OK);
    332         return false;
    333     }
    334
    335     /****
    336      * Get the mailbox status.  A status attempt can only
    337      * succeed if the client is in the
    338      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    339      * TRANSACTION_STATE </a>.  Returns a POP3MessageInfo instance
    340      * containing the number of messages in the mailbox and the total
    341      * size of the messages in bytes.  Returns null if the status the
    342      * attempt fails.
    343      * <p>
    344      * @return A POP3MessageInfo instance containing the number of
    345      *         messages in the mailbox and the total size of the messages
    346      *         in bytes.  Returns null if the status the attempt fails.
    347      * @exception IOException If a network I/O error occurs in the process of
    348      *       sending the status command.
    349      ***/
    350     public POP3MessageInfo status() throws IOException
    351     {
    352         if (getState() != TRANSACTION_STATE)
    353             return null;
    354         if (sendCommand(POP3Command.STAT) != POP3Reply.OK)
    355             return null;
    356         return __parseStatus(_lastReplyLine.substring(3));
    357     }
    358
    359
    360     /****
    361      * List an individual message.  A list attempt can only
    362      * succeed if the client is in the
    363      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    364      * TRANSACTION_STATE </a>.  Returns a POP3MessageInfo instance
    365      * containing the number of the listed message and the
    366      * size of the message in bytes.  Returns null if the list
    367      * attempt fails (e.g., if the specified message number does
    368      * not exist).
    369      * <p>
    370      * @param messageId  The number of the message list.
    371      * @return A POP3MessageInfo instance containing the number of the
    372      *         listed message and the size of the message in bytes.  Returns
    373      *         null if the list attempt fails.
    374      * @exception IOException If a network I/O error occurs in the process of
    375      *         sending the list command.
    376      ***/
    377     public POP3MessageInfo listMessage(int messageId) throws IOException
    378     {
    379         if (getState() != TRANSACTION_STATE)
    380             return null;
    381         if (sendCommand(POP3Command.LIST, Integer.toString(messageId))
    382                 != POP3Reply.OK)
    383             return null;
    384         return __parseStatus(_lastReplyLine.substring(3));
    385     }
    386
    387
    388     /****
    389      * List all messages.  A list attempt can only
    390      * succeed if the client is in the
    391      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    392      * TRANSACTION_STATE </a>.  Returns an array of POP3MessageInfo instances,
    393      * each containing the number of a message and its size in bytes.
    394      * If there are no messages, this method returns a zero length array.
    395      * If the list attempt fails, it returns null.
    396      * <p>
    397      * @return An array of POP3MessageInfo instances representing all messages
    398      * in the order they appear in the mailbox,
    399      * each containing the number of a message and its size in bytes.
    400      * If there are no messages, this method returns a zero length array.
    401      * If the list attempt fails, it returns null.
    402      * @exception IOException If a network I/O error occurs in the process of
    403      *     sending the list command.
    404      ***/
    405     public POP3MessageInfo[] listMessages() throws IOException
    406     {
    407         POP3MessageInfo[] messages;
    408         Enumeration enum;
    409         int line;
    410
    411         if (getState() != TRANSACTION_STATE)
    412             return null;
    413         if (sendCommand(POP3Command.LIST) != POP3Reply.OK)
    414             return null;
    415         getAdditionalReply();
    416
    417         // This could be a zero length array if no messages present
    418         messages = new POP3MessageInfo[_replyLines.size() - 2];
    419         enum = _replyLines.elements();
    420
    421         // Skip first line
    422         enum.nextElement();
    423
    424         // Fetch lines.
    425         for (line = 0; line < messages.length; line++)
    426             messages[line] = __parseStatus((String)enum.nextElement());
    427
    428         return messages;
    429     }
    430
    431     /****
    432      * List the unique identifier for a message.  A list attempt can only
    433      * succeed if the client is in the
    434      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    435      * TRANSACTION_STATE </a>.  Returns a POP3MessageInfo instance
    436      * containing the number of the listed message and the
    437      * unique identifier for that message.  Returns null if the list
    438      * attempt fails  (e.g., if the specified message number does
    439      * not exist).
    440      * <p>
    441      * @param messageId  The number of the message list.
    442      * @return A POP3MessageInfo instance containing the number of the
    443      *         listed message and the unique identifier for that message.
    444      *         Returns null if the list attempt fails.
    445      * @exception IOException If a network I/O error occurs in the process of
    446      *        sending the list unique identifier command.
    447      ***/
    448     public POP3MessageInfo listUniqueIdentifier(int messageId)
    449     throws IOException
    450     {
    451         if (getState() != TRANSACTION_STATE)
    452             return null;
    453         if (sendCommand(POP3Command.UIDL, Integer.toString(messageId))
    454                 != POP3Reply.OK)
    455             return null;
    456         return __parseUID(_lastReplyLine.substring(3));
    457     }
    458
    459
    460     /****
    461      * List the unique identifiers for all messages.  A list attempt can only
    462      * succeed if the client is in the
    463      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    464      * TRANSACTION_STATE </a>.  Returns an array of POP3MessageInfo instances,
    465      * each containing the number of a message and its unique identifier.
    466      * If there are no messages, this method returns a zero length array.
    467      * If the list attempt fails, it returns null.
    468      * <p>
    469      * @return An array of POP3MessageInfo instances representing all messages
    470      * in the order they appear in the mailbox,
    471      * each containing the number of a message and its unique identifier
    472      * If there are no messages, this method returns a zero length array.
    473      * If the list attempt fails, it returns null.
    474      * @exception IOException If a network I/O error occurs in the process of
    475      *     sending the list unique identifier command.
    476      ***/
    477     public POP3MessageInfo[] listUniqueIdentifiers() throws IOException
    478     {
    479         POP3MessageInfo[] messages;
    480         Enumeration enum;
    481         int line;
    482
    483         if (getState() != TRANSACTION_STATE)
    484             return null;
    485         if (sendCommand(POP3Command.UIDL) != POP3Reply.OK)
    486             return null;
    487         getAdditionalReply();
    488
    489         // This could be a zero length array if no messages present
    490         messages = new POP3MessageInfo[_replyLines.size() - 2];
    491         enum = _replyLines.elements();
    492
    493         // Skip first line
    494         enum.nextElement();
    495
    496         // Fetch lines.
    497         for (line = 0; line < messages.length; line++)
    498             messages[line] = __parseUID((String)enum.nextElement());
    499
    500         return messages;
    501     }
    502
    503
    504     /****
    505      * Retrieve a message from the POP3 server.  A retrieve message attempt
    506      * can only succeed if the client is in the
    507      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    508      * TRANSACTION_STATE </a>.  Returns a DotTerminatedMessageReader instance
    509      * from which the entire message can be read.
    510      * Returns null if the retrieval attempt fails  (e.g., if the specified
    511      * message number does not exist).
    512      * <p>
    513      * You must not issue any commands to the POP3 server (i.e., call any
    514      * other methods) until you finish reading the message from the
    515      * returned Reader instance.
    516      * The POP3 protocol uses the same stream for issuing commands as it does
    517      * for returning results.  Therefore the returned Reader actually reads
    518      * directly from the POP3 connection.  After the end of message has been
    519      * reached, new commands can be executed and their replies read.  If
    520      * you do not follow these requirements, your program will not work
    521      * properly.
    522      * <p>
    523      * @param messageId  The number of the message to fetch.
    524      * @return A DotTerminatedMessageReader instance
    525      * from which the entire message can be read.
    526      * Returns null if the retrieval attempt fails  (e.g., if the specified
    527      * message number does not exist).
    528      * @exception IOException If a network I/O error occurs in the process of
    529      *        sending the retrieve message command.
    530      ***/
    531     public Reader retrieveMessage(int messageId) throws IOException
    532     {
    533         if (getState() != TRANSACTION_STATE)
    534             return null;
    535         if (sendCommand(POP3Command.RETR, Integer.toString(messageId))
    536                 != POP3Reply.OK)
    537             return null;
    538
    539         return new DotTerminatedMessageReader(_reader);
    540     }
    541
    542
    543     /****
    544      * Retrieve only the specified top number of lines of a message from the
    545      * POP3 server.  A retrieve top lines attempt
    546      * can only succeed if the client is in the
    547      * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE">
    548      * TRANSACTION_STATE </a>.  Returns a DotTerminatedMessageReader instance
    549      * from which the specified top number of lines of the message can be
    550      * read.
    551      * Returns null if the retrieval attempt fails  (e.g., if the specified
    552      * message number does not exist).
    553      * <p>
    554      * You must not issue any commands to the POP3 server (i.e., call any
    555      * other methods) until you finish reading the message from the returned
    556      * Reader instance.
    557      * The POP3 protocol uses the same stream for issuing commands as it does
    558      * for returning results.  Therefore the returned Reader actually reads
    559      * directly from the POP3 connection.  After the end of message has been
    560      * reached, new commands can be executed and their replies read.  If
    561      * you do not follow these requirements, your program will not work
    562      * properly.
    563      * <p>
    564      * @param messageId  The number of the message to fetch.
    565      * @param numLines  The top number of lines to fetch. This must be >= 0.
    566      * @return  A DotTerminatedMessageReader instance
    567      * from which the specified top number of lines of the message can be
    568      * read.
    569      * Returns null if the retrieval attempt fails  (e.g., if the specified
    570      * message number does not exist).
    571      * @exception IOException If a network I/O error occurs in the process of
    572      *       sending the top command.
    573      ***/
    574     public Reader retrieveMessageTop(int messageId, int numLines)
    575     throws IOException
    576     {
    577         if (numLines < 0 || getState() != TRANSACTION_STATE)
    578             return null;
    579         if (sendCommand(POP3Command.TOP, Integer.toString(messageId) + " " +
    580                         Integer.toString(numLines)) != POP3Reply.OK)
    581             return null;
    582
    583         return new DotTerminatedMessageReader(_reader);
    584     }
    585
    586
    587 }
    588

This page was automatically generated by Maven