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; */