/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2000-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.net.mail; import totalcross.io.IOException; import totalcross.net.SocketTimeoutException; import totalcross.sys.Convert; import totalcross.sys.InvalidNumberException; import totalcross.sys.Vm; import totalcross.util.Hashtable; import totalcross.util.Vector; /** * A POP3 Folder (can only be "INBOX"). * * @since TotalCross 1.13 */ public class POP3Folder extends Folder { protected POP3Folder(Store store) { super(store); } public void open() throws MessagingException { if (messageCount != -1) // already open return; try { msgHeaderBuffer = new byte[Math.min(256*1024,HEADER_BUFFER_SIZE)]; store.connection.writeBytes("STAT "+Convert.CRLF); String stat = store.connection.readLine(); messageCount = Convert.toInt(stat.substring(4, stat.indexOf(' ', 4))); messagesByUidl = new Hashtable(messageCount); messagesByNumber = new Hashtable(messageCount); expungedMessages = new Hashtable(messageCount / 10); } catch (InvalidNumberException e) { throw new MessagingException(e); } catch (IOException e) { throw new MessagingException(e); } } public Message getMessage(int msgNumber) throws MessagingException { if (messageCount == -1) // not open return null; Message msgRet = (Message) messagesByNumber.get(msgNumber); if (msgRet != null) return msgRet; try { String reply; String uidl; store.connection.writeBytes("UIDL " + msgNumber + Convert.CRLF); reply = store.connection.readLine(); if (reply.startsWith("-ERR")) return null; uidl = reply.substring(reply.lastIndexOf(' ') + 1); msgRet = (Message) messagesByUidl.get(uidl); if (msgRet == null) { store.connection.writeBytes("LIST " + msgNumber + Convert.CRLF); reply = store.connection.readLine(); if (!reply.startsWith("+OK")) throw new MessagingException("Server replied: "+reply); int msgSize = Convert.toInt(reply.substring(reply.lastIndexOf(' ') + 1)) + 3; int top = msgSize <= HEADER_BUFFER_SIZE ? msgSize : 0; store.connection.writeBytes("TOP " + msgNumber + " " + top + Convert.CRLF); reply = store.connection.readLine(); int bytesRead; int totalRead = 0; try { do { if (totalRead == HEADER_BUFFER_SIZE) { HEADER_BUFFER_SIZE *= 1.1; byte[] newBuf = new byte[HEADER_BUFFER_SIZE]; Vm.arrayCopy(msgHeaderBuffer, 0, newBuf, 0, totalRead); msgHeaderBuffer = newBuf; } bytesRead = store.connection.readBytes(msgHeaderBuffer, totalRead, msgHeaderBuffer.length - totalRead); if (bytesRead > 0) totalRead += bytesRead; } while (!new String(msgHeaderBuffer, totalRead - 5, 5).equals("\r\n.\r\n")); } catch (SocketTimeoutException e) { if (!new String(msgHeaderBuffer, totalRead - 5, 5).equals("\r\n.\r\n")) throw new MessagingException(e); } msgRet = new Message(this, msgNumber, uidl, msgSize, totalRead); String s = new String(msgHeaderBuffer, 0, totalRead - 5); if (top > 0) { int msgIndex = s.indexOf("\r\n\r\n"); msgRet.parseHeader(s.substring(0, msgIndex)); msgRet.parseContent(s.substring(msgIndex + 4)); // +4 to skip double CRLF } else msgRet.parseHeader(s); messagesByUidl.put(uidl, msgRet); messagesByNumber.put(msgNumber, msgRet); } } catch (InvalidNumberException e) { try {store.connection.close();} catch (IOException ee) {} throw new MessagingException(e); } catch (AddressException e) { try {store.connection.close();} catch (IOException ee) {} throw new MessagingException(e); } catch (IOException e) { try {store.connection.close();} catch (IOException ee) {} throw new MessagingException(e); } return msgRet; } public Message getMessage(String uidl) throws MessagingException { if (messageCount == -1) // not open return null; return (Message) messagesByUidl.get(uidl); } public void reset() throws MessagingException { try { String reply; store.connection.writeBytes("RSET "+Convert.CRLF); reply = store.connection.readLine(); if (reply.startsWith("+OK")) { Vector keys = expungedMessages.getKeys(); for (int i = keys.size() - 1; i >= 0; i--) { Message msg = (Message) expungedMessages.remove(keys.items[i]); msg.expunged = false; messagesByUidl.put(msg.uidl, msg); deletedMessageCount = 0; } } } catch (IOException e) { throw new MessagingException(e); } } void deleteMessage(Message message) throws MessagingException { try { String reply; store.connection.writeBytes("DELE " + message.msgNumber + Convert.CRLF); reply = store.connection.readLine(); if (reply.startsWith("+OK")) { message.expunged = true; messagesByUidl.remove(message.uidl); expungedMessages.put(message.uidl, message); deletedMessageCount++; } } catch (IOException e) { throw new MessagingException(e); } } }