View Javadoc
1 package org.apache.commons.net.pop3; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Commons" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.io.IOException; 58 import java.io.Reader; 59 import java.security.MessageDigest; 60 import java.security.NoSuchAlgorithmException; 61 import java.util.Enumeration; 62 import java.util.StringTokenizer; 63 import org.apache.commons.net.io.DotTerminatedMessageReader; 64 65 /**** 66 * The POP3Client class implements the client side of the Internet POP3 67 * Protocol defined in RFC 1939. All commands are supported, including 68 * the APOP command which requires MD5 encryption. See RFC 1939 for 69 * more details on the POP3 protocol. 70 * <p> 71 * Rather than list it separately for each method, we mention here that 72 * every method communicating with the server and throwing an IOException 73 * can also throw a 74 * <a href="org.apache.commons.net.MalformedServerReplyException.html"> 75 * MalformedServerReplyException </a>, which is a subclass 76 * of IOException. A MalformedServerReplyException will be thrown when 77 * the reply received from the server deviates enough from the protocol 78 * specification that it cannot be interpreted in a useful manner despite 79 * attempts to be as lenient as possible. 80 * <p> 81 * <p> 82 * @author Daniel F. Savarese 83 * @see POP3MessageInfo 84 * @see org.apache.commons.net.io.DotTerminatedMessageReader 85 * @see org.apache.commons.net.MalformedServerReplyException 86 ***/ 87 88 public class POP3Client extends POP3 89 { 90 91 private static POP3MessageInfo __parseStatus(String line) 92 { 93 int num, size; 94 StringTokenizer tokenizer; 95 96 tokenizer = new StringTokenizer(line); 97 98 if (!tokenizer.hasMoreElements()) 99 return null; 100 101 num = size = 0; 102 103 try 104 { 105 num = Integer.parseInt(tokenizer.nextToken()); 106 107 if (!tokenizer.hasMoreElements()) 108 return null; 109 110 size = Integer.parseInt(tokenizer.nextToken()); 111 } 112 catch (NumberFormatException e) 113 { 114 return null; 115 } 116 117 return new POP3MessageInfo(num, size); 118 } 119 120 private static POP3MessageInfo __parseUID(String line) 121 { 122 int num; 123 StringTokenizer tokenizer; 124 125 tokenizer = new StringTokenizer(line); 126 127 if (!tokenizer.hasMoreElements()) 128 return null; 129 130 num = 0; 131 132 try 133 { 134 num = Integer.parseInt(tokenizer.nextToken()); 135 136 if (!tokenizer.hasMoreElements()) 137 return null; 138 139 line = tokenizer.nextToken(); 140 } 141 catch (NumberFormatException e) 142 { 143 return null; 144 } 145 146 return new POP3MessageInfo(num, line); 147 } 148 149 /**** 150 * Login to the POP3 server with the given username and password. You 151 * must first connect to the server with 152 * <a href="org.apache.commons.net.SocketClient.html#connect"> connect </a> 153 * before attempting to login. A login attempt is only valid if 154 * the client is in the 155 * <a href="org.apache.commons.net.pop3.POP3.html#AUTHORIZATION_STATE"> 156 * AUTHORIZATION_STATE </a>. After logging in, the client enters the 157 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 158 * TRANSACTION_STATE </a>. 159 * <p> 160 * @param username The account name being logged in to. 161 * @param password The plain text password of the account. 162 * @return True if the login attempt was successful, false if not. 163 * @exception IOException If a network I/O error occurs in the process of 164 * logging in. 165 ***/ 166 public boolean login(String username, String password) throws IOException 167 { 168 if (getState() != AUTHORIZATION_STATE) 169 return false; 170 171 if (sendCommand(POP3Command.USER, username) != POP3Reply.OK) 172 return false; 173 174 if (sendCommand(POP3Command.PASS, password) != POP3Reply.OK) 175 return false; 176 177 setState(TRANSACTION_STATE); 178 179 return true; 180 } 181 182 183 /**** 184 * Login to the POP3 server with the given username and authentication 185 * information. Use this method when connecting to a server requiring 186 * authentication using the APOP command. Because the timestamp 187 * produced in the greeting banner varies from server to server, it is 188 * not possible to consistently extract the information. Therefore, 189 * after connecting to the server, you must call 190 * <a href="org.apache.commons.net.pop3.POP3.html#getReplyString"> 191 * getReplyString </a> and parse out the timestamp information yourself. 192 * <p> 193 * You must first connect to the server with 194 * <a href="org.apache.commons.net.SocketClient.html#connect"> connect </a> 195 * before attempting to login. A login attempt is only valid if 196 * the client is in the 197 * <a href="org.apache.commons.net.pop3.POP3.html#AUTHORIZATION_STATE"> 198 * AUTHORIZATION_STATE </a>. After logging in, the client enters the 199 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 200 * TRANSACTION_STATE </a>. After connecting, you must parse out the 201 * server specific information to use as a timestamp, and pass that 202 * information to this method. The secret is a shared secret known 203 * to you and the server. See RFC 1939 for more details regarding 204 * the APOP command. 205 * <p> 206 * @param username The account name being logged in to. 207 * @param timestamp The timestamp string to combine with the secret. 208 * @param secret The shared secret which produces the MD5 digest when 209 * combined with the timestamp. 210 * @return True if the login attempt was successful, false if not. 211 * @exception IOException If a network I/O error occurs in the process of 212 * logging in. 213 * @exception NoSuchAlgorithmException If the MD5 encryption algorithm 214 * cannot be instantiated by the Java runtime system. 215 ***/ 216 public boolean login(String username, String timestamp, String secret) 217 throws IOException, NoSuchAlgorithmException 218 { 219 int i; 220 byte[] digest; 221 StringBuffer buffer, digestBuffer; 222 MessageDigest md5; 223 224 if (getState() != AUTHORIZATION_STATE) 225 return false; 226 227 md5 = MessageDigest.getInstance("MD5"); 228 timestamp += secret; 229 digest = md5.digest(timestamp.getBytes()); 230 digestBuffer = new StringBuffer(128); 231 232 for (i = 0; i < digest.length; i++) 233 digestBuffer.append(Integer.toHexString(digest[i] & 0xff)); 234 235 buffer = new StringBuffer(256); 236 buffer.append(username); 237 buffer.append(' '); 238 buffer.append(digestBuffer.toString()); 239 240 if (sendCommand(POP3Command.APOP, buffer.toString()) != POP3Reply.OK) 241 return false; 242 243 setState(TRANSACTION_STATE); 244 245 return true; 246 } 247 248 249 /**** 250 * Logout of the POP3 server. To fully disconnect from the server 251 * you must call 252 * <a href="org.apache.commons.net.pop3.POP3.html#disconnect"> disconnect </a>. 253 * A logout attempt is valid in any state. If 254 * the client is in the 255 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 256 * TRANSACTION_STATE </a>, it enters the 257 * <a href="org.apache.commons.net.pop3.POP3.html#UPDATE_STATE"> 258 * UPDATE_STATE </a> on a successful logout. 259 * <p> 260 * @return True if the logout attempt was successful, false if not. 261 * @exception IOException If a network I/O error occurs in the process 262 * of logging out. 263 ***/ 264 public boolean logout() throws IOException 265 { 266 if (getState() == TRANSACTION_STATE) 267 setState(UPDATE_STATE); 268 sendCommand(POP3Command.QUIT); 269 return (_replyCode == POP3Reply.OK); 270 } 271 272 273 /**** 274 * Send a NOOP command to the POP3 server. This is useful for keeping 275 * a connection alive since most POP3 servers will timeout after 10 276 * minutes of inactivity. A noop attempt will only succeed if 277 * the client is in the 278 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 279 * TRANSACTION_STATE </a>. 280 * <p> 281 * @return True if the noop attempt was successful, false if not. 282 * @exception IOException If a network I/O error occurs in the process of 283 * sending the NOOP command. 284 ***/ 285 public boolean noop() throws IOException 286 { 287 if (getState() == TRANSACTION_STATE) 288 return (sendCommand(POP3Command.NOOP) == POP3Reply.OK); 289 return false; 290 } 291 292 293 /**** 294 * Delete a message from the POP3 server. The message is only marked 295 * for deletion by the server. If you decide to unmark the message, you 296 * must issuse a <a href="#reset"> reset </a> command. Messages marked 297 * for deletion are only deleted by the server on 298 * <a href="#logout"> logout </a>. 299 * A delete attempt can only succeed if the client is in the 300 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 301 * TRANSACTION_STATE </a>. 302 * <p> 303 * @param messageId The message number to delete. 304 * @return True if the deletion attempt was successful, false if not. 305 * @exception IOException If a network I/O error occurs in the process of 306 * sending the delete command. 307 ***/ 308 public boolean deleteMessage(int messageId) throws IOException 309 { 310 if (getState() == TRANSACTION_STATE) 311 return (sendCommand(POP3Command.DELE, Integer.toString(messageId)) 312 == POP3Reply.OK); 313 return false; 314 } 315 316 317 /**** 318 * Reset the POP3 session. This is useful for undoing any message 319 * deletions that may have been performed. A reset attempt can only 320 * succeed if the client is in the 321 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 322 * TRANSACTION_STATE </a>. 323 * <p> 324 * @return True if the reset attempt was successful, false if not. 325 * @exception IOException If a network I/O error occurs in the process of 326 * sending the reset command. 327 ***/ 328 public boolean reset() throws IOException 329 { 330 if (getState() == TRANSACTION_STATE) 331 return (sendCommand(POP3Command.RSET) == POP3Reply.OK); 332 return false; 333 } 334 335 /**** 336 * Get the mailbox status. A status attempt can only 337 * succeed if the client is in the 338 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 339 * TRANSACTION_STATE </a>. Returns a POP3MessageInfo instance 340 * containing the number of messages in the mailbox and the total 341 * size of the messages in bytes. Returns null if the status the 342 * attempt fails. 343 * <p> 344 * @return A POP3MessageInfo instance containing the number of 345 * messages in the mailbox and the total size of the messages 346 * in bytes. Returns null if the status the attempt fails. 347 * @exception IOException If a network I/O error occurs in the process of 348 * sending the status command. 349 ***/ 350 public POP3MessageInfo status() throws IOException 351 { 352 if (getState() != TRANSACTION_STATE) 353 return null; 354 if (sendCommand(POP3Command.STAT) != POP3Reply.OK) 355 return null; 356 return __parseStatus(_lastReplyLine.substring(3)); 357 } 358 359 360 /**** 361 * List an individual message. A list attempt can only 362 * succeed if the client is in the 363 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 364 * TRANSACTION_STATE </a>. Returns a POP3MessageInfo instance 365 * containing the number of the listed message and the 366 * size of the message in bytes. Returns null if the list 367 * attempt fails (e.g., if the specified message number does 368 * not exist). 369 * <p> 370 * @param messageId The number of the message list. 371 * @return A POP3MessageInfo instance containing the number of the 372 * listed message and the size of the message in bytes. Returns 373 * null if the list attempt fails. 374 * @exception IOException If a network I/O error occurs in the process of 375 * sending the list command. 376 ***/ 377 public POP3MessageInfo listMessage(int messageId) throws IOException 378 { 379 if (getState() != TRANSACTION_STATE) 380 return null; 381 if (sendCommand(POP3Command.LIST, Integer.toString(messageId)) 382 != POP3Reply.OK) 383 return null; 384 return __parseStatus(_lastReplyLine.substring(3)); 385 } 386 387 388 /**** 389 * List all messages. A list attempt can only 390 * succeed if the client is in the 391 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 392 * TRANSACTION_STATE </a>. Returns an array of POP3MessageInfo instances, 393 * each containing the number of a message and its size in bytes. 394 * If there are no messages, this method returns a zero length array. 395 * If the list attempt fails, it returns null. 396 * <p> 397 * @return An array of POP3MessageInfo instances representing all messages 398 * in the order they appear in the mailbox, 399 * each containing the number of a message and its size in bytes. 400 * If there are no messages, this method returns a zero length array. 401 * If the list attempt fails, it returns null. 402 * @exception IOException If a network I/O error occurs in the process of 403 * sending the list command. 404 ***/ 405 public POP3MessageInfo[] listMessages() throws IOException 406 { 407 POP3MessageInfo[] messages; 408 Enumeration enum; 409 int line; 410 411 if (getState() != TRANSACTION_STATE) 412 return null; 413 if (sendCommand(POP3Command.LIST) != POP3Reply.OK) 414 return null; 415 getAdditionalReply(); 416 417 // This could be a zero length array if no messages present 418 messages = new POP3MessageInfo[_replyLines.size() - 2]; 419 enum = _replyLines.elements(); 420 421 // Skip first line 422 enum.nextElement(); 423 424 // Fetch lines. 425 for (line = 0; line < messages.length; line++) 426 messages[line] = __parseStatus((String)enum.nextElement()); 427 428 return messages; 429 } 430 431 /**** 432 * List the unique identifier for a message. A list attempt can only 433 * succeed if the client is in the 434 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 435 * TRANSACTION_STATE </a>. Returns a POP3MessageInfo instance 436 * containing the number of the listed message and the 437 * unique identifier for that message. Returns null if the list 438 * attempt fails (e.g., if the specified message number does 439 * not exist). 440 * <p> 441 * @param messageId The number of the message list. 442 * @return A POP3MessageInfo instance containing the number of the 443 * listed message and the unique identifier for that message. 444 * Returns null if the list attempt fails. 445 * @exception IOException If a network I/O error occurs in the process of 446 * sending the list unique identifier command. 447 ***/ 448 public POP3MessageInfo listUniqueIdentifier(int messageId) 449 throws IOException 450 { 451 if (getState() != TRANSACTION_STATE) 452 return null; 453 if (sendCommand(POP3Command.UIDL, Integer.toString(messageId)) 454 != POP3Reply.OK) 455 return null; 456 return __parseUID(_lastReplyLine.substring(3)); 457 } 458 459 460 /**** 461 * List the unique identifiers for all messages. A list attempt can only 462 * succeed if the client is in the 463 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 464 * TRANSACTION_STATE </a>. Returns an array of POP3MessageInfo instances, 465 * each containing the number of a message and its unique identifier. 466 * If there are no messages, this method returns a zero length array. 467 * If the list attempt fails, it returns null. 468 * <p> 469 * @return An array of POP3MessageInfo instances representing all messages 470 * in the order they appear in the mailbox, 471 * each containing the number of a message and its unique identifier 472 * If there are no messages, this method returns a zero length array. 473 * If the list attempt fails, it returns null. 474 * @exception IOException If a network I/O error occurs in the process of 475 * sending the list unique identifier command. 476 ***/ 477 public POP3MessageInfo[] listUniqueIdentifiers() throws IOException 478 { 479 POP3MessageInfo[] messages; 480 Enumeration enum; 481 int line; 482 483 if (getState() != TRANSACTION_STATE) 484 return null; 485 if (sendCommand(POP3Command.UIDL) != POP3Reply.OK) 486 return null; 487 getAdditionalReply(); 488 489 // This could be a zero length array if no messages present 490 messages = new POP3MessageInfo[_replyLines.size() - 2]; 491 enum = _replyLines.elements(); 492 493 // Skip first line 494 enum.nextElement(); 495 496 // Fetch lines. 497 for (line = 0; line < messages.length; line++) 498 messages[line] = __parseUID((String)enum.nextElement()); 499 500 return messages; 501 } 502 503 504 /**** 505 * Retrieve a message from the POP3 server. A retrieve message attempt 506 * can only succeed if the client is in the 507 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 508 * TRANSACTION_STATE </a>. Returns a DotTerminatedMessageReader instance 509 * from which the entire message can be read. 510 * Returns null if the retrieval attempt fails (e.g., if the specified 511 * message number does not exist). 512 * <p> 513 * You must not issue any commands to the POP3 server (i.e., call any 514 * other methods) until you finish reading the message from the 515 * returned Reader instance. 516 * The POP3 protocol uses the same stream for issuing commands as it does 517 * for returning results. Therefore the returned Reader actually reads 518 * directly from the POP3 connection. After the end of message has been 519 * reached, new commands can be executed and their replies read. If 520 * you do not follow these requirements, your program will not work 521 * properly. 522 * <p> 523 * @param messageId The number of the message to fetch. 524 * @return A DotTerminatedMessageReader instance 525 * from which the entire message can be read. 526 * Returns null if the retrieval attempt fails (e.g., if the specified 527 * message number does not exist). 528 * @exception IOException If a network I/O error occurs in the process of 529 * sending the retrieve message command. 530 ***/ 531 public Reader retrieveMessage(int messageId) throws IOException 532 { 533 if (getState() != TRANSACTION_STATE) 534 return null; 535 if (sendCommand(POP3Command.RETR, Integer.toString(messageId)) 536 != POP3Reply.OK) 537 return null; 538 539 return new DotTerminatedMessageReader(_reader); 540 } 541 542 543 /**** 544 * Retrieve only the specified top number of lines of a message from the 545 * POP3 server. A retrieve top lines attempt 546 * can only succeed if the client is in the 547 * <a href="org.apache.commons.net.pop3.POP3.html#TRANSACTION_STATE"> 548 * TRANSACTION_STATE </a>. Returns a DotTerminatedMessageReader instance 549 * from which the specified top number of lines of the message can be 550 * read. 551 * Returns null if the retrieval attempt fails (e.g., if the specified 552 * message number does not exist). 553 * <p> 554 * You must not issue any commands to the POP3 server (i.e., call any 555 * other methods) until you finish reading the message from the returned 556 * Reader instance. 557 * The POP3 protocol uses the same stream for issuing commands as it does 558 * for returning results. Therefore the returned Reader actually reads 559 * directly from the POP3 connection. After the end of message has been 560 * reached, new commands can be executed and their replies read. If 561 * you do not follow these requirements, your program will not work 562 * properly. 563 * <p> 564 * @param messageId The number of the message to fetch. 565 * @param numLines The top number of lines to fetch. This must be >= 0. 566 * @return A DotTerminatedMessageReader instance 567 * from which the specified top number of lines of the message can be 568 * read. 569 * Returns null if the retrieval attempt fails (e.g., if the specified 570 * message number does not exist). 571 * @exception IOException If a network I/O error occurs in the process of 572 * sending the top command. 573 ***/ 574 public Reader retrieveMessageTop(int messageId, int numLines) 575 throws IOException 576 { 577 if (numLines < 0 || getState() != TRANSACTION_STATE) 578 return null; 579 if (sendCommand(POP3Command.TOP, Integer.toString(messageId) + " " + 580 Integer.toString(numLines)) != POP3Reply.OK) 581 return null; 582 583 return new DotTerminatedMessageReader(_reader); 584 } 585 586 587 } 588

This page was automatically generated by Maven