View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.imap;
19  
20  import java.io.IOException;
21  
22  /**
23   * The IMAPClient class provides the basic functionalities found in an
24   * IMAP client.
25   */
26  public class IMAPClient extends IMAP
27  {
28  
29      private static final char DQUOTE = '"';
30      private static final String DQUOTE_S = "\"";
31  
32      // --------- commands available in all states
33  
34      /**
35       * Send a CAPABILITY command to the server.
36       * @return {@code true} if the command was successful,{@code false} if not.
37       * @throws IOException If a network I/O error occurs
38       */
39      public boolean capability() throws IOException
40      {
41          return doCommand (IMAPCommand.CAPABILITY);
42      }
43  
44      /**
45       * Send a NOOP command to the server.  This is useful for keeping
46       * a connection alive since most IMAP servers will timeout after 10
47       * minutes of inactivity.
48       * @return {@code true} if the command was successful,{@code false} if not.
49       * @throws IOException If a network I/O error occurs.
50       */
51      public boolean noop() throws IOException
52      {
53          return doCommand (IMAPCommand.NOOP);
54      }
55  
56      /**
57       * Send a LOGOUT command to the server.  To fully disconnect from the server
58       * you must call disconnect().
59       * A logout attempt is valid in any state.  If
60       * the client is in the not authenticated or authenticated state, it enters the
61       * logout on a successful logout.
62       * @return {@code true} if the command was successful,{@code false} if not.
63       * @throws IOException If a network I/O error occurs.
64       */
65      public boolean logout() throws IOException
66      {
67          return doCommand (IMAPCommand.LOGOUT);
68      }
69  
70      // --------- commands available in the not-authenticated state
71      // STARTTLS skipped - see IMAPSClient.
72      // AUTHENTICATE skipped - see AuthenticatingIMAPClient.
73  
74      /**
75       * Login to the IMAP server with the given username and password.  You
76       * must first connect to the server with
77       * {@link org.apache.commons.net.SocketClient#connect  connect }
78       * before attempting to login.  A login attempt is only valid if
79       * the client is in the NOT_AUTH_STATE.
80       * After logging in, the client enters the AUTH_STATE.
81       *
82       * @param username  The account name being logged in to.
83       * @param password  The plain text password of the account.
84       * @return True if the login attempt was successful, false if not.
85       * @throws IOException If a network I/O error occurs in the process of
86       *            logging in.
87       */
88      public boolean login(final String username, final String password) throws IOException
89      {
90          if (getState() != IMAP.IMAPState.NOT_AUTH_STATE)
91          {
92              return false;
93          }
94  
95          if (!doCommand(IMAPCommand.LOGIN, username + " " + password))
96          {
97              return false;
98          }
99  
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; */