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(String username, 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(String mailboxName) throws IOException
114    {
115        return doCommand (IMAPCommand.SELECT, 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(String mailboxName) throws IOException
125    {
126        return doCommand (IMAPCommand.EXAMINE, 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(String mailboxName) throws IOException
136    {
137        return doCommand (IMAPCommand.CREATE, 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(String mailboxName) throws IOException
147    {
148        return doCommand (IMAPCommand.DELETE, 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(String oldMailboxName, String newMailboxName) throws IOException
159    {
160        return doCommand (IMAPCommand.RENAME, oldMailboxName + " " + 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(String mailboxName) throws IOException
170    {
171        return doCommand (IMAPCommand.SUBSCRIBE, 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(String mailboxName) throws IOException
181    {
182        return doCommand (IMAPCommand.UNSUBSCRIBE, mailboxName);
183    }
184
185    /**
186     * Send a LIST command to the server.
187     * @param refName The reference name.
188     * @param mailboxName The mailbox name.
189     * @return {@code true} if the command was successful,{@code false} if not.
190     * @throws IOException If a network I/O error occurs.
191     */
192    public boolean list(String refName, String mailboxName) throws IOException
193    {
194        return doCommand (IMAPCommand.LIST, refName + " " + mailboxName);
195    }
196
197    /**
198     * Send an LSUB command to the server.
199     * @param refName The reference name.
200     * @param mailboxName The mailbox name.
201     * @return {@code true} if the command was successful,{@code false} if not.
202     * @throws IOException If a network I/O error occurs.
203     */
204    public boolean lsub(String refName, String mailboxName) throws IOException
205    {
206        return doCommand (IMAPCommand.LSUB, refName + " " + mailboxName);
207    }
208
209    /**
210     * Send a STATUS command to the server.
211     * @param mailboxName The reference name.
212     * @param itemNames The status data item names.
213     * @return {@code true} if the command was successful,{@code false} if not.
214     * @throws IOException If a network I/O error occurs.
215     */
216    public boolean status(String mailboxName, String[] itemNames) throws IOException
217    {
218        if (itemNames == null || itemNames.length < 1) {
219            throw new IllegalArgumentException("STATUS command requires at least one data item name");
220        }
221
222        StringBuilder sb = new StringBuilder();
223        sb.append(mailboxName);
224
225        sb.append(" (");
226        for ( int i = 0; i < itemNames.length; i++ )
227        {
228            if (i > 0) {
229                sb.append(" ");
230            }
231            sb.append(itemNames[i]);
232        }
233        sb.append(")");
234
235        return doCommand (IMAPCommand.STATUS, sb.toString());
236    }
237
238    /**
239     * Send an APPEND command to the server.
240     * @param mailboxName The mailbox name.
241     * @param flags The flag parenthesized list (optional).
242     * @param datetime The date/time string (optional).
243     * @param message The message to append.
244     * @return {@code true} if the command was successful,{@code false} if not.
245     * @throws IOException If a network I/O error occurs.
246     * @since 3.4
247     */
248    public boolean append(String mailboxName, String flags, String datetime, String message) throws IOException
249    {
250        StringBuilder args = new StringBuilder(mailboxName);
251        if (flags != null) {
252            args.append(" ").append(flags);
253        }
254        if (datetime != null) {
255            args.append(" ");
256            if (datetime.charAt(0) == DQUOTE) {
257                args.append(datetime);
258            } else {
259                args.append(DQUOTE).append(datetime).append(DQUOTE);
260            }
261        }
262        args.append(" ");
263        // String literal (probably not used much - it at all)
264        if (message.startsWith(DQUOTE_S) && message.endsWith(DQUOTE_S)) {
265            args.append(message);
266            return doCommand (IMAPCommand.APPEND, args.toString());
267        }
268        args.append('{').append(message.length()).append('}'); // length of message
269        final int status = sendCommand(IMAPCommand.APPEND, args.toString());
270        return IMAPReply.isContinuation(status) // expecting continuation response
271            && IMAPReply.isSuccess(sendData(message)); // if so, send the data
272    }
273
274    /**
275     * Send an APPEND command to the server.
276     * @param mailboxName The mailbox name.
277     * @param flags The flag parenthesized list (optional).
278     * @param datetime The date/time string (optional).
279     * @return {@code true} if the command was successful,{@code false} if not.
280     * @throws IOException If a network I/O error occurs.
281     * @deprecated (3.4) Does not work; the message body is not optional.
282     * Use {@link #append(String, String, String, String)} instead.
283     */
284    @Deprecated
285    public boolean append(String mailboxName, String flags, String datetime) throws IOException
286    {
287        String args = mailboxName;
288        if (flags != null) {
289            args += " " + flags;
290        }
291        if (datetime != null) {
292            if (datetime.charAt(0) == '{') {
293                args += " " + datetime;
294            } else {
295                args += " {" + datetime + "}";
296            }
297        }
298        return doCommand (IMAPCommand.APPEND, args);
299    }
300
301    /**
302     * Send an APPEND command to the server.
303     * @param mailboxName The mailbox name.
304     * @return {@code true} if the command was successful,{@code false} if not.
305     * @throws IOException If a network I/O error occurs.
306     * @deprecated (3.4) Does not work; the message body is not optional.
307     * Use {@link #append(String, String, String, String)} instead.
308     */
309    @Deprecated
310    public boolean append(String mailboxName) throws IOException
311    {
312        return append(mailboxName, null, null);
313    }
314
315    // --------- commands available in the selected state
316
317    /**
318     * Send a CHECK command to the server.
319     * @return {@code true} if the command was successful,{@code false} if not.
320     * @throws IOException If a network I/O error occurs.
321     */
322    public boolean check() throws IOException
323    {
324        return doCommand (IMAPCommand.CHECK);
325    }
326
327    /**
328     * Send a CLOSE command to the server.
329     * @return {@code true} if the command was successful,{@code false} if not.
330     * @throws IOException If a network I/O error occurs.
331     */
332    public boolean close() throws IOException
333    {
334        return doCommand (IMAPCommand.CLOSE);
335    }
336
337    /**
338     * Send an EXPUNGE command to the server.
339     * @return {@code true} if the command was successful,{@code false} if not.
340     * @throws IOException If a network I/O error occurs.
341     */
342    public boolean expunge() throws IOException
343    {
344        return doCommand (IMAPCommand.EXPUNGE);
345    }
346
347    /**
348     * Send a SEARCH command to the server.
349     * @param charset The charset (optional).
350     * @param criteria The search criteria.
351     * @return {@code true} if the command was successful,{@code false} if not.
352     * @throws IOException If a network I/O error occurs.
353     */
354    public boolean search(String charset, String criteria) throws IOException
355    {
356        String args = "";
357        if (charset != null) {
358            args += "CHARSET " + charset;
359        }
360        args += criteria;
361        return doCommand (IMAPCommand.SEARCH, args);
362    }
363
364    /**
365     * Send a SEARCH command to the server.
366     * @param criteria The search criteria.
367     * @return {@code true} if the command was successful,{@code false} if not.
368     * @throws IOException If a network I/O error occurs.
369     */
370    public boolean search(String criteria) throws IOException
371    {
372        return search(null, criteria);
373    }
374
375    /**
376     * Send a FETCH command to the server.
377     *
378     * @param sequenceSet The sequence set to fetch (e.g. 1:4,6,11,100:*)
379     * @param itemNames The item names for the FETCH command. (e.g. BODY.PEEK[HEADER.FIELDS (SUBJECT)])
380     * If multiple item names are requested, these must be enclosed in parentheses, e.g. "(UID FLAGS BODY.PEEK[])"
381     * @return {@code true} if the command was successful,{@code false} if not.
382     * @throws IOException If a network I/O error occurs.
383     * @see #getReplyString()
384     * @see #getReplyStrings()
385     */
386    public boolean fetch(String sequenceSet, String itemNames) throws IOException
387    {
388        return doCommand (IMAPCommand.FETCH, sequenceSet + " " + itemNames);
389    }
390
391    /**
392     * Send a STORE command to the server.
393     * @param sequenceSet The sequence set to update (e.g. 2:5)
394     * @param itemNames The item name for the STORE command (i.e. [+|-]FLAGS[.SILENT])
395     * @param itemValues The item values for the STORE command. (e.g. (\Deleted) )
396     * @return {@code true} if the command was successful,{@code false} if not.
397     * @throws IOException If a network I/O error occurs.
398     */
399    public boolean store(String sequenceSet, String itemNames, String itemValues)
400        throws IOException
401    {
402        return doCommand (IMAPCommand.STORE, sequenceSet + " " + itemNames + " " + itemValues);
403    }
404
405    /**
406     * Send a COPY command to the server.
407     * @param sequenceSet The sequence set to fetch.
408     * @param mailboxName The mailbox name.
409     * @return {@code true} if the command was successful,{@code false} if not.
410     * @throws IOException If a network I/O error occurs.
411     */
412    public boolean copy(String sequenceSet, String mailboxName) throws IOException
413    {
414        return doCommand (IMAPCommand.COPY, sequenceSet + " " + mailboxName);
415    }
416
417    /**
418     * Send a UID command to the server.
419     * @param command The command for UID.
420     * @param commandArgs The arguments for the command.
421     * @return {@code true} if the command was successful,{@code false} if not.
422     * @throws IOException If a network I/O error occurs.
423     */
424    public boolean uid(String command, String commandArgs) throws IOException
425    {
426        return doCommand (IMAPCommand.UID, command + " " + commandArgs);
427    }
428
429    /**
430     * The status data items defined in RFC 3501.
431     */
432    public enum STATUS_DATA_ITEMS
433    {
434        /** The number of messages in the mailbox. */
435        MESSAGES,
436        /** The number of messages with the \Recent flag set. */
437        RECENT,
438        /** The next unique identifier value of the mailbox. */
439        UIDNEXT,
440        /** The unique identifier validity value of the mailbox. */
441        UIDVALIDITY,
442        /** The number of messages which do not have the \Seen flag set. */
443        UNSEEN;
444    }
445
446    /**
447     * The search criteria defined in RFC 3501.
448     */
449    public enum SEARCH_CRITERIA
450    {
451        /** All messages in the mailbox. */
452        ALL,
453        /** Messages with the \Answered flag set. */
454        ANSWERED,
455        /**
456         * Messages that contain the specified string in the envelope
457         * structure's BCC field.
458         */
459        BCC,
460        /**
461         * Messages whose internal date (disregarding time and timezone)
462         * is earlier than the specified date.
463         */
464        BEFORE,
465        /**
466         * Messages that contain the specified string in the body of the
467         * message.
468         */
469        BODY,
470        /**
471         * Messages that contain the specified string in the envelope
472         * structure's CC field.
473         */
474        CC,
475        /** Messages with the \Deleted flag set. */
476        DELETED,
477        /** Messages with the \Draft flag set. */
478        DRAFT,
479        /** Messages with the \Flagged flag set. */
480        FLAGGED,
481        /**
482         * Messages that contain the specified string in the envelope
483         * structure's FROM field.
484         */
485        FROM,
486        /**
487         * Messages that have a header with the specified field-name (as
488         * defined in [RFC-2822]) and that contains the specified string
489         * in the text of the header (what comes after the colon).  If the
490         * string to search is zero-length, this matches all messages that
491         * have a header line with the specified field-name regardless of
492         * the contents.
493         */
494        HEADER,
495        /** Messages with the specified keyword flag set. */
496        KEYWORD,
497        /**
498         * Messages with an [RFC-2822] size larger than the specified
499         * number of octets.
500         */
501        LARGER,
502        /**
503         * Messages that have the \Recent flag set but not the \Seen flag.
504         * This is functionally equivalent to "(RECENT UNSEEN)".
505         */
506        NEW,
507        /** Messages that do not match the specified search key. */
508        NOT,
509        /**
510         * Messages that do not have the \Recent flag set.  This is
511         * functionally equivalent to "NOT RECENT" (as opposed to "NOT
512         * NEW").
513         */
514        OLD,
515        /**
516         * Messages whose internal date (disregarding time and timezone)
517         * is within the specified date.
518         */
519        ON,
520        /** Messages that match either search key. */
521        OR,
522        /** Messages that have the \Recent flag set. */
523        RECENT,
524        /** Messages that have the \Seen flag set. */
525        SEEN,
526        /**
527         * Messages whose [RFC-2822] Date: header (disregarding time and
528         * timezone) is earlier than the specified date.
529         */
530        SENTBEFORE,
531        /**
532         * Messages whose [RFC-2822] Date: header (disregarding time and
533         * timezone) is within the specified date.
534         */
535        SENTON,
536        /**
537         * Messages whose [RFC-2822] Date: header (disregarding time and
538         * timezone) is within or later than the specified date.
539         */
540        SENTSINCE,
541        /**
542         * Messages whose internal date (disregarding time and timezone)
543         * is within or later than the specified date.
544         */
545        SINCE,
546        /**
547         * Messages with an [RFC-2822] size smaller than the specified
548         * number of octets.
549         */
550        SMALLER,
551        /**
552         * Messages that contain the specified string in the envelope
553         * structure's SUBJECT field.
554         */
555        SUBJECT,
556        /**
557         * Messages that contain the specified string in the header or
558         * body of the message.
559         */
560        TEXT,
561        /**
562         * Messages that contain the specified string in the envelope
563         * structure's TO field.
564         */
565        TO,
566        /**
567         * Messages with unique identifiers corresponding to the specified
568         * unique identifier set.  Sequence set ranges are permitted.
569         */
570        UID,
571        /** Messages that do not have the \Answered flag set. */
572        UNANSWERED,
573        /** Messages that do not have the \Deleted flag set. */
574        UNDELETED,
575        /** Messages that do not have the \Draft flag set. */
576        UNDRAFT,
577        /** Messages that do not have the \Flagged flag set. */
578        UNFLAGGED,
579        /** Messages that do not have the specified keyword flag set. */
580        UNKEYWORD,
581        /** Messages that do not have the \Seen flag set. */
582        UNSEEN;
583    }
584
585    /**
586     * The message data item names for the FETCH command defined in RFC 3501.
587     */
588    public enum FETCH_ITEM_NAMES
589    {
590        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE). */
591        ALL,
592        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE). */
593        FAST,
594        /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY). */
595        FULL,
596        /** Non-extensible form of BODYSTRUCTURE or the text of a particular body section. */
597        BODY,
598        /** The [MIME-IMB] body structure of the message. */
599        BODYSTRUCTURE,
600        /** The envelope structure of the message. */
601        ENVELOPE,
602        /** The flags that are set for this message. */
603        FLAGS,
604        /** The internal date of the message. */
605        INTERNALDATE,
606        /** A prefix for RFC-822 item names. */
607        RFC822,
608        /** The unique identifier for the message. */
609        UID;
610    }
611
612}
613/* kate: indent-width 4; replace-tabs on; */