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       * @exception 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       * @exception 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       * @exception 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       * @exception IOException If a network I/O error occurs in the process of
86       *            logging in.
87       */
88      public boolean login(String username, 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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      * @exception 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; */