    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.net.imap;
    019
    020import java.io.IOException;
    021
    022/**
    023 * The IMAPClient class provides the basic functionalities found in an
    024 * IMAP client.
    025 */
    026public class IMAPClient extends IMAP
    027{
    028
    029    private static final char DQUOTE = '"';
    030    private static final String DQUOTE_S = "\"";
    031
    032    // --------- commands available in all states
    033
    034    /**
    035     * Send a CAPABILITY command to the server.
    036     * @return {@code true} if the command was successful,{@code false} if not.
    037     * @throws IOException If a network I/O error occurs
    038     */
    039    public boolean capability() throws IOException
    040    {
    041        return doCommand (IMAPCommand.CAPABILITY);
    042    }
    043
    044    /**
    045     * Send a NOOP command to the server.  This is useful for keeping
    046     * a connection alive since most IMAP servers will timeout after 10
    047     * minutes of inactivity.
    048     * @return {@code true} if the command was successful,{@code false} if not.
    049     * @throws IOException If a network I/O error occurs.
    050     */
    051    public boolean noop() throws IOException
    052    {
    053        return doCommand (IMAPCommand.NOOP);
    054    }
    055
    056    /**
    057     * Send a LOGOUT command to the server.  To fully disconnect from the server
    058     * you must call disconnect().
    059     * A logout attempt is valid in any state.  If
    060     * the client is in the not authenticated or authenticated state, it enters the
    061     * logout on a successful logout.
    062     * @return {@code true} if the command was successful,{@code false} if not.
    063     * @throws IOException If a network I/O error occurs.
    064     */
    065    public boolean logout() throws IOException
    066    {
    067        return doCommand (IMAPCommand.LOGOUT);
    068    }
    069
    070    // --------- commands available in the not-authenticated state
    071    // STARTTLS skipped - see IMAPSClient.
    072    // AUTHENTICATE skipped - see AuthenticatingIMAPClient.
    073
    074    /**
    075     * Login to the IMAP server with the given username and password.  You
    076     * must first connect to the server with
    077     * {@link org.apache.commons.net.SocketClient#connect  connect }
    078     * before attempting to login.  A login attempt is only valid if
    079     * the client is in the NOT_AUTH_STATE.
    080     * After logging in, the client enters the AUTH_STATE.
    081     *
    082     * @param username  The account name being logged in to.
    083     * @param password  The plain text password of the account.
    084     * @return True if the login attempt was successful, false if not.
    085     * @throws IOException If a network I/O error occurs in the process of
    086     *            logging in.
    087     */
    088    public boolean login(final String username, final String password) throws IOException
    089    {
    090        if (getState() != IMAP.IMAPState.NOT_AUTH_STATE)
    091        {
    092            return false;
    093        }
    094
    095        if (!doCommand(IMAPCommand.LOGIN, username + " " + password))
    096        {
    097            return false;
    098        }
    099
    100        setState(IMAP.IMAPState.AUTH_STATE);
    101
    102        return true;
    103    }
    104
    105    // --------- commands available in the authenticated state
    106
    107    /**
    108     * Send a SELECT command to the server.
    109     * @param mailboxName The mailbox name to select.
    110     * @return {@code true} if the command was successful,{@code false} if not.
    111     * @throws IOException If a network I/O error occurs.
    112     */
    113    public boolean select(final String mailboxName) throws IOException
    114    {
    115        return doCommand (IMAPCommand.SELECT, quoteMailboxName(mailboxName));
    116    }
    117
    118    /**
    119     * Send an EXAMINE command to the server.
    120     * @param mailboxName The mailbox name to examine.
    121     * @return {@code true} if the command was successful,{@code false} if not.
    122     * @throws IOException If a network I/O error occurs.
    123     */
    124    public boolean examine(final String mailboxName) throws IOException
    125    {
    126        return doCommand (IMAPCommand.EXAMINE, quoteMailboxName(mailboxName));
    127    }
    128
    129    /**
    130     * Send a CREATE command to the server.
    131     * @param mailboxName The mailbox name to create.
    132     * @return {@code true} if the command was successful,{@code false} if not.
    133     * @throws IOException If a network I/O error occurs.
    134     */
    135    public boolean create(final String mailboxName) throws IOException
    136    {
    137        return doCommand (IMAPCommand.CREATE, quoteMailboxName(mailboxName));
    138    }
    139
    140    /**
    141     * Send a DELETE command to the server.
    142     * @param mailboxName The mailbox name to delete.
    143     * @return {@code true} if the command was successful,{@code false} if not.
    144     * @throws IOException If a network I/O error occurs.
    145     */
    146    public boolean delete(final String mailboxName) throws IOException
    147    {
    148        return doCommand (IMAPCommand.DELETE, quoteMailboxName(mailboxName));
    149    }
    150
    151    /**
    152     * Send a RENAME command to the server.
    153     * @param oldMailboxName The existing mailbox name to rename.
    154     * @param newMailboxName The new mailbox name.
    155     * @return {@code true} if the command was successful,{@code false} if not.
    156     * @throws IOException If a network I/O error occurs.
    157     */
    158    public boolean rename(final String oldMailboxName, final String newMailboxName) throws IOException
    159    {
    160        return doCommand (IMAPCommand.RENAME, quoteMailboxName(oldMailboxName) + " " + quoteMailboxName(newMailboxName));
    161    }
    162
    163    /**
    164     * Send a SUBSCRIBE command to the server.
    165     * @param mailboxName The mailbox name to subscribe to.
    166     * @return {@code true} if the command was successful,{@code false} if not.
    167     * @throws IOException If a network I/O error occurs.
    168     */
    169    public boolean subscribe(final String mailboxName) throws IOException
    170    {
    171        return doCommand (IMAPCommand.SUBSCRIBE, quoteMailboxName(mailboxName));
    172    }
    173
    174    /**
    175     * Send a UNSUBSCRIBE command to the server.
    176     * @param mailboxName The mailbox name to unsubscribe from.
    177     * @return {@code true} if the command was successful,{@code false} if not.
    178     * @throws IOException If a network I/O error occurs.
    179     */
    180    public boolean unsubscribe(final String mailboxName) throws IOException
    181    {
    182        return doCommand (IMAPCommand.UNSUBSCRIBE, quoteMailboxName(mailboxName));
    183    }
    184
    185    /**
    186     * Send a LIST command to the server.
    187     * Quotes the parameters if necessary.
    188     * @param refName The reference name
    189     *                If empty, indicates that the mailbox name is interpreted as by SELECT.
    190     * @param mailboxName The mailbox name.
    191     *                     If empty, this is a special request to
    192     *                     return the hierarchy delimiter and the root name of the name given
    193     *                     in the reference
    194     * @return {@code true} if the command was successful,{@code false} if not.
    195     * @throws IOException If a network I/O error occurs.
    196     */
    197    public boolean list(final String refName, final String mailboxName) throws IOException
    198    {
    199        return doCommand (IMAPCommand.LIST, quoteMailboxName(refName) + " " + quoteMailboxName(mailboxName));
    200    }
    201
    202    /**
    203     * Send an LSUB command to the server.
    204     * Quotes the parameters if necessary.
    205     * @param refName The reference name.
    206     * @param mailboxName The mailbox name.
    207     * @return {@code true} if the command was successful,{@code false} if not.
    208     * @throws IOException If a network I/O error occurs.
    209     */
    210    public boolean lsub(final String refName, final String mailboxName) throws IOException
    211    {
    212        return doCommand (IMAPCommand.LSUB, quoteMailboxName(refName) + " " + quoteMailboxName(mailboxName));
    213    }
    214
    215    /**
    216     * Send a STATUS command to the server.
    217     * @param mailboxName The reference name.
    218     * @param itemNames The status data item names.
    219     * @return {@code true} if the command was successful,{@code false} if not.
    220     * @throws IOException If a network I/O error occurs.
    221     */
    222    public boolean status(final String mailboxName, final String[] itemNames) throws IOException
    223    {
    224        if (itemNames == null || itemNames.length < 1) {
    225            throw new IllegalArgumentException("STATUS command requires at least one data item name");
    226        }
    227
    228        final StringBuilder sb = new StringBuilder();
    229        sb.append(quoteMailboxName(mailboxName));
    230
    231        sb.append(" (");
    232        for ( int i = 0; i < itemNames.length; i++ )
    233        {
    234            if (i > 0) {
    235                sb.append(" ");
    236            }
    237            sb.append(itemNames[i]);
    238        }
    239        sb.append(")");
    240
    241        return doCommand (IMAPCommand.STATUS, sb.toString());
    242    }
    243
    244    /**
    245     * Send an APPEND command to the server.
    246     * @param mailboxName The mailbox name.
    247     * @param flags The flag parenthesized list (optional).
    248     * @param datetime The date/time string (optional).
    249     * @param message The message to append.
    250     * @return {@code true} if the command was successful,{@code false} if not.
    251     * @throws IOException If a network I/O error occurs.
    252     * @since 3.4
    253     */
    254    public boolean append(final String mailboxName, final String flags, final String datetime, final String message)
    255            throws IOException {
    256        final StringBuilder args = new StringBuilder(quoteMailboxName(mailboxName));
    257        if (flags != null) {
    258            args.append(" ").append(flags);
    259        }
    260        if (datetime != null) {
    261            args.append(" ");
    262            if (datetime.charAt(0) == DQUOTE) {
    263                args.append(datetime);
    264            } else {
    265                args.append(DQUOTE).append(datetime).append(DQUOTE);
    266            }
    267        }
    268        args.append(" ");
    269        // String literal (probably not used much - if at all)
    270        if (message.startsWith(DQUOTE_S) && message.endsWith(DQUOTE_S)) {
    271            args.append(message);
    272            return doCommand(IMAPCommand.APPEND, args.toString());
    273        }
    274        args.append('{').append(message.getBytes(IMAP.__DEFAULT_ENCODING).length).append('}'); // length of message
    275        final int status = sendCommand(IMAPCommand.APPEND, args.toString());
    276        return IMAPReply.isContinuation(status) // expecting continuation response
    277                && IMAPReply.isSuccess(sendData(message)); // if so, send the data
    278    }
    279
    280    /**
    281     * Send an APPEND command to the server.
    282     * @param mailboxName The mailbox name.
    283     * @param flags The flag parenthesized list (optional).
    284     * @param datetime The date/time string (optional).
    285     * @return {@code true} if the command was successful,{@code false} if not.
    286     * @throws IOException If a network I/O error occurs.
    287     * @deprecated (3.4) Does not work; the message body is not optional.
    288     * Use {@link #append(String, String, String, String)} instead.
    289     */
    290    @Deprecated
    291    public boolean append(final String mailboxName, final String flags, final String datetime) throws IOException
    292    {
    293        String args = mailboxName;
    294        if (flags != null) {
    295            args += " " + flags;
    296        }
    297        if (datetime != null) {
    298            if (datetime.charAt(0) == '{') {
    299                args += " " + datetime;
    300            } else {
    301                args += " {" + datetime + "}";
    302            }
    303        }
    304        return doCommand (IMAPCommand.APPEND, args);
    305    }
    306
    307    /**
    308     * Send an APPEND command to the server.
    309     * @param mailboxName The mailbox name.
    310     * @return {@code true} if the command was successful,{@code false} if not.
    311     * @throws IOException If a network I/O error occurs.
    312     * @deprecated (3.4) Does not work; the message body is not optional.
    313     * Use {@link #append(String, String, String, String)} instead.
    314     */
    315    @Deprecated
    316    public boolean append(final String mailboxName) throws IOException
    317    {
    318        return append(mailboxName, null, null);
    319    }
    320
    321    // --------- commands available in the selected state
    322
    323    /**
    324     * Send a CHECK command to the server.
    325     * @return {@code true} if the command was successful,{@code false} if not.
    326     * @throws IOException If a network I/O error occurs.
    327     */
    328    public boolean check() throws IOException
    329    {
    330        return doCommand (IMAPCommand.CHECK);
    331    }
    332
    333    /**
    334     * Send a CLOSE command to the server.
    335     * @return {@code true} if the command was successful,{@code false} if not.
    336     * @throws IOException If a network I/O error occurs.
    337     */
    338    public boolean close() throws IOException
    339    {
    340        return doCommand (IMAPCommand.CLOSE);
    341    }
    342
    343    /**
    344     * Send an EXPUNGE command to the server.
    345     * @return {@code true} if the command was successful,{@code false} if not.
    346     * @throws IOException If a network I/O error occurs.
    347     */
    348    public boolean expunge() throws IOException
    349    {
    350        return doCommand (IMAPCommand.EXPUNGE);
    351    }
    352
    353    /**
    354     * Send a SEARCH command to the server.
    355     * @param charset The charset (optional).
    356     * @param criteria The search criteria.
    357     * @return {@code true} if the command was successful,{@code false} if not.
    358     * @throws IOException If a network I/O error occurs.
    359     */
    360    public boolean search(final String charset, final String criteria) throws IOException
    361    {
    362        String args = "";
    363        if (charset != null) {
    364            args += "CHARSET " + charset;
    365        }
    366        args += criteria;
    367        return doCommand (IMAPCommand.SEARCH, args);
    368    }
    369
    370    /**
    371     * Send a SEARCH command to the server.
    372     * @param criteria The search criteria.
    373     * @return {@code true} if the command was successful,{@code false} if not.
    374     * @throws IOException If a network I/O error occurs.
    375     */
    376    public boolean search(final String criteria) throws IOException
    377    {
    378        return search(null, criteria);
    379    }
    380
    381    /**
    382     * Send a FETCH command to the server.
    383     *
    384     * @param sequenceSet The sequence set to fetch (e.g. 1:4,6,11,100:*)
    385     * @param itemNames The item names for the FETCH command. (e.g. BODY.PEEK[HEADER.FIELDS (SUBJECT)])
    386     * If multiple item names are requested, these must be enclosed in parentheses, e.g. "(UID FLAGS BODY.PEEK[])"
    387     * @return {@code true} if the command was successful,{@code false} if not.
    388     * @throws IOException If a network I/O error occurs.
    389     * @see #getReplyString()
    390     * @see #getReplyStrings()
    391     */
    392    public boolean fetch(final String sequenceSet, final String itemNames) throws IOException
    393    {
    394        return doCommand (IMAPCommand.FETCH, sequenceSet + " " + itemNames);
    395    }
    396
    397    /**
    398     * Send a STORE command to the server.
    399     * @param sequenceSet The sequence set to update (e.g. 2:5)
    400     * @param itemNames The item name for the STORE command (i.e. [+|-]FLAGS[.SILENT])
    401     * @param itemValues The item values for the STORE command. (e.g. (\Deleted) )
    402     * @return {@code true} if the command was successful,{@code false} if not.
    403     * @throws IOException If a network I/O error occurs.
    404     */
    405    public boolean store(final String sequenceSet, final String itemNames, final String itemValues)
    406        throws IOException
    407    {
    408        return doCommand (IMAPCommand.STORE, sequenceSet + " " + itemNames + " " + itemValues);
    409    }
    410
    411    /**
    412     * Send a COPY command to the server.
    413     * @param sequenceSet The sequence set to fetch.
    414     * @param mailboxName The mailbox name.
    415     * @return {@code true} if the command was successful,{@code false} if not.
    416     * @throws IOException If a network I/O error occurs.
    417     */
    418    public boolean copy(final String sequenceSet, final String mailboxName) throws IOException
    419    {
    420        return doCommand (IMAPCommand.COPY, sequenceSet + " " + quoteMailboxName(mailboxName));
    421    }
    422
    423    /**
    424     * Send a UID command to the server.
    425     * @param command The command for UID.
    426     * @param commandArgs The arguments for the command.
    427     * @return {@code true} if the command was successful,{@code false} if not.
    428     * @throws IOException If a network I/O error occurs.
    429     */
    430    public boolean uid(final String command, final String commandArgs) throws IOException
    431    {
    432        return doCommand (IMAPCommand.UID, command + " " + commandArgs);
    433    }
    434
    435    /**
    436     * The status data items defined in RFC 3501.
    437     */
    438    public enum STATUS_DATA_ITEMS
    439    {
    440        /** The number of messages in the mailbox. */
    441        MESSAGES,
    442        /** The number of messages with the \Recent flag set. */
    443        RECENT,
    444        /** The next unique identifier value of the mailbox. */
    445        UIDNEXT,
    446        /** The unique identifier validity value of the mailbox. */
    447        UIDVALIDITY,
    448        /** The number of messages which do not have the \Seen flag set. */
    449        UNSEEN
    450    }
    451
    452    /**
    453     * The search criteria defined in RFC 3501.
    454     */
    455    public enum SEARCH_CRITERIA
    456    {
    457        /** All messages in the mailbox. */
    458        ALL,
    459        /** Messages with the \Answered flag set. */
    460        ANSWERED,
    461        /**
    462         * Messages that contain the specified string in the envelope
    463         * structure's BCC field.
    464         */
    465        BCC,
    466        /**
    467         * Messages whose internal date (disregarding time and time zone)
    468         * is earlier than the specified date.
    469         */
    470        BEFORE,
    471        /**
    472         * Messages that contain the specified string in the body of the
    473         * message.
    474         */
    475        BODY,
    476        /**
    477         * Messages that contain the specified string in the envelope
    478         * structure's CC field.
    479         */
    480        CC,
    481        /** Messages with the \Deleted flag set. */
    482        DELETED,
    483        /** Messages with the \Draft flag set. */
    484        DRAFT,
    485        /** Messages with the \Flagged flag set. */
    486        FLAGGED,
    487        /**
    488         * Messages that contain the specified string in the envelope
    489         * structure's FROM field.
    490         */
    491        FROM,
    492        /**
    493         * Messages that have a header with the specified field-name (as
    494         * defined in [RFC-2822]) and that contains the specified string
    495         * in the text of the header (what comes after the colon).  If the
    496         * string to search is zero-length, this matches all messages that
    497         * have a header line with the specified field-name regardless of
    498         * the contents.
    499         */
    500        HEADER,
    501        /** Messages with the specified keyword flag set. */
    502        KEYWORD,
    503        /**
    504         * Messages with an [RFC-2822] size larger than the specified
    505         * number of octets.
    506         */
    507        LARGER,
    508        /**
    509         * Messages that have the \Recent flag set but not the \Seen flag.
    510         * This is functionally equivalent to "(RECENT UNSEEN)".
    511         */
    512        NEW,
    513        /** Messages that do not match the specified search key. */
    514        NOT,
    515        /**
    516         * Messages that do not have the \Recent flag set.  This is
    517         * functionally equivalent to "NOT RECENT" (as opposed to "NOT
    518         * NEW").
    519         */
    520        OLD,
    521        /**
    522         * Messages whose internal date (disregarding time and time zone)
    523         * is within the specified date.
    524         */
    525        ON,
    526        /** Messages that match either search key. */
    527        OR,
    528        /** Messages that have the \Recent flag set. */
    529        RECENT,
    530        /** Messages that have the \Seen flag set. */
    531        SEEN,
    532        /**
    533         * Messages whose [RFC-2822] Date: header (disregarding time and
    534         * time zone) is earlier than the specified date.
    535         */
    536        SENTBEFORE,
    537        /**
    538         * Messages whose [RFC-2822] Date: header (disregarding time and
    539         * time zone) is within the specified date.
    540         */
    541        SENTON,
    542        /**
    543         * Messages whose [RFC-2822] Date: header (disregarding time and
    544         * time zone) is within or later than the specified date.
    545         */
    546        SENTSINCE,
    547        /**
    548         * Messages whose internal date (disregarding time and time zone)
    549         * is within or later than the specified date.
    550         */
    551        SINCE,
    552        /**
    553         * Messages with an [RFC-2822] size smaller than the specified
    554         * number of octets.
    555         */
    556        SMALLER,
    557        /**
    558         * Messages that contain the specified string in the envelope
    559         * structure's SUBJECT field.
    560         */
    561        SUBJECT,
    562        /**
    563         * Messages that contain the specified string in the header or
    564         * body of the message.
    565         */
    566        TEXT,
    567        /**
    568         * Messages that contain the specified string in the envelope
    569         * structure's TO field.
    570         */
    571        TO,
    572        /**
    573         * Messages with unique identifiers corresponding to the specified
    574         * unique identifier set.  Sequence set ranges are permitted.
    575         */
    576        UID,
    577        /** Messages that do not have the \Answered flag set. */
    578        UNANSWERED,
    579        /** Messages that do not have the \Deleted flag set. */
    580        UNDELETED,
    581        /** Messages that do not have the \Draft flag set. */
    582        UNDRAFT,
    583        /** Messages that do not have the \Flagged flag set. */
    584        UNFLAGGED,
    585        /** Messages that do not have the specified keyword flag set. */
    586        UNKEYWORD,
    587        /** Messages that do not have the \Seen flag set. */
    588        UNSEEN
    589    }
    590
    591    /**
    592     * The message data item names for the FETCH command defined in RFC 3501.
    593     */
    594    public enum FETCH_ITEM_NAMES
    595    {
    596        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE). */
    597        ALL,
    598        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE). */
    599        FAST,
    600        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY). */
    601        FULL,
    602        /** Non-extensible form of BODYSTRUCTURE or the text of a particular body section. */
    603        BODY,
    604        /** The [MIME-IMB] body structure of the message. */
    605        BODYSTRUCTURE,
    606        /** The envelope structure of the message. */
    607        ENVELOPE,
    608        /** The flags that are set for this message. */
    609        FLAGS,
    610        /** The internal date of the message. */
    611        INTERNALDATE,
    612        /** A prefix for RFC-822 item names. */
    613        RFC822,
    614        /** The unique identifier for the message. */
    615        UID
    616    }
    617
    618}
    619/* kate: indent-width 4; replace-tabs on; */