You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by do...@apache.org on 2013/08/21 18:35:18 UTC

svn commit: r1516205 [5/9] - in /james/hupa/trunk: ./ client/src/main/java/org/apache/hupa/ client/src/main/java/org/apache/hupa/client/ client/src/main/java/org/apache/hupa/client/gin/ client/src/main/java/org/apache/hupa/client/mvp/ client/src/main/j...

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractDeleteMessageHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractDeleteMessageHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractDeleteMessageHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractDeleteMessageHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,123 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import javax.mail.Flags;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.DeleteMessage;
+import org.apache.hupa.shared.rpc.DeleteMessageResult;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Abstract class which should get extended by all handlers which needs to handle message deletion
+ *
+ * @param <Action>
+ */
+public abstract class AbstractDeleteMessageHandler<Action extends DeleteMessage>
+        extends AbstractSessionHandler<Action, DeleteMessageResult> {
+
+    @Inject
+    public AbstractDeleteMessageHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> sessionProvider) {
+        super(cache, logger, sessionProvider);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.hupa.server.handler.AbstractSessionHandler#executeInternal(org.apache.hupa.shared.rpc.Session, net.customware.gwt.dispatch.server.ExecutionContext)
+     */
+    public DeleteMessageResult executeInternal(Action action,
+            ExecutionContext context) throws ActionException {
+        org.apache.hupa.shared.data.IMAPFolder folder = action.getFolder();
+        User user = getUser();
+        try {
+            IMAPStore store = cache.get(user);
+            com.sun.mail.imap.IMAPFolder f = (com.sun.mail.imap.IMAPFolder) store
+                    .getFolder(folder.getFullName());
+            // check if the folder is open, if not open it "rw"
+            if (f.isOpen() == false) {
+                f.open(com.sun.mail.imap.IMAPFolder.READ_WRITE);
+            }
+
+            Message[] mArray = getMessagesToDelete(action);
+            
+            // check if the delete was triggered not in the trash folder
+            if (folder.getFullName().equalsIgnoreCase(
+                    user.getSettings().getTrashFolderName()) == false) {
+                com.sun.mail.imap.IMAPFolder trashFolder = (com.sun.mail.imap.IMAPFolder) store
+                        .getFolder(user.getSettings().getTrashFolderName());
+
+                boolean trashFound = false;
+                // if the trash folder does not exist we create it
+                if (trashFolder.exists() == false) {
+                    trashFound = trashFolder
+                            .create(com.sun.mail.imap.IMAPFolder.READ_WRITE);
+                } else {
+                    trashFound = true;
+                }
+
+                // Check if we are able to copy the messages to the trash folder
+                if (trashFound) {
+                    // copy the messages to the trashfolder
+                    f.copyMessages(mArray, trashFolder);
+                }
+            }
+
+            
+            // delete the messages from the folder
+            f.setFlags(mArray, new Flags(Flags.Flag.DELETED), true);
+            
+            try {
+                f.expunge(mArray);
+                f.close(false);
+            } catch (MessagingException e) {
+                // prolly UID expunge is not supported
+                f.close(true);
+            }
+            return new DeleteMessageResult(user, folder, mArray.length);
+
+        } catch (MessagingException e) {
+            logger.error("Error while deleting messages for user " + user
+                    + " in folder" + action.getFolder(), e);
+            throw new ActionException("Error while deleting messages");
+        }
+    }
+
+    /**
+     * Return an array holding all messages which should get deleted by the given action
+     * 
+     * @param action
+     * @return messages
+     * @throws ActionException
+     */
+    protected abstract Message[] getMessagesToDelete(Action action) throws ActionException;
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractFetchMessagesHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractFetchMessagesHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractFetchMessagesHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractFetchMessagesHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,272 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import com.google.inject.Provider;
+
+import com.sun.mail.imap.IMAPStore;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.server.preferences.UserPreferencesStorage;
+import org.apache.hupa.shared.data.IMAPFolder;
+import org.apache.hupa.shared.data.Tag;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.data.Message.IMAPFlag;
+import org.apache.hupa.shared.rpc.FetchMessages;
+import org.apache.hupa.shared.rpc.FetchMessagesResult;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+import javax.mail.Address;
+import javax.mail.FetchProfile;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Part;
+import javax.mail.internet.MimeUtility;
+import javax.mail.internet.MimeMessage.RecipientType;
+import javax.servlet.http.HttpSession;
+
+public abstract class AbstractFetchMessagesHandler <A extends FetchMessages> extends AbstractSessionHandler<A, FetchMessagesResult>{
+
+    UserPreferencesStorage userPreferences;
+    
+    public AbstractFetchMessagesHandler(IMAPStoreCache cache, Log logger, Provider<HttpSession> sessionProvider, UserPreferencesStorage preferences) {
+        super(cache, logger, sessionProvider);
+        this.userPreferences = preferences;
+    }
+
+    @Override
+    protected FetchMessagesResult executeInternal(A action,
+            ExecutionContext context) throws ActionException {
+        User user = getUser();
+        IMAPFolder folder = action.getFolder();
+        if (folder == null) {
+            folder = new IMAPFolder(user.getSettings().getInboxFolderName());
+        }
+        com.sun.mail.imap.IMAPFolder f = null;
+        int start = action.getStart();
+        int offset = action.getOffset();
+        try {
+            IMAPStore store = cache.get(user);
+            
+            f =  (com.sun.mail.imap.IMAPFolder)store.getFolder(folder.getFullName());
+
+             // check if the folder is open, if not open it read only
+            if (f.isOpen() == false) {
+                f.open(com.sun.mail.imap.IMAPFolder.READ_ONLY);
+            }
+
+            // if the folder is empty we have no need to process 
+            int exists = f.getMessageCount();
+            if (exists == 0) {
+                 return new FetchMessagesResult(new ArrayList<org.apache.hupa.shared.data.Message>(), start, offset, 0, 0);
+            }        
+            
+            MessageConvertArray convArray = getMessagesToConvert(f,action);
+            return new FetchMessagesResult(convert(offset, f, convArray.getMesssages()),start, offset,convArray.getRealCount(),f.getUnreadMessageCount());
+        } catch (MessagingException e) {
+            logger.info("Error fetching messages in folder: " + folder.getFullName() + " " + e.getMessage());
+            // Folder can not contain messages
+            return new FetchMessagesResult(new ArrayList<org.apache.hupa.shared.data.Message>(), start, offset, 0, 0);
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error("Error while fetching headers for user " + user.getName() + " in folder " + folder,e);
+            throw new ActionException(
+                    "Error while fetching headers for user " + user.getName() + " in folder " + folder);
+        
+        } finally {
+            if (f != null && f.isOpen()) {
+                try {
+                    f.close(false);
+                } catch (MessagingException e) {
+                    // we don't care to much about an exception on close here...
+                }
+            }
+        }
+    }
+    
+    protected abstract MessageConvertArray getMessagesToConvert(com.sun.mail.imap.IMAPFolder f, A action) throws MessagingException, ActionException;
+    
+    protected ArrayList<org.apache.hupa.shared.data.Message> convert(int offset, com.sun.mail.imap.IMAPFolder folder, Message[] messages) throws MessagingException {
+        ArrayList<org.apache.hupa.shared.data.Message> mList = new ArrayList<org.apache.hupa.shared.data.Message>();
+        // Setup fetchprofile to limit the stuff which is fetched 
+        FetchProfile fp = new FetchProfile();
+        fp.add(FetchProfile.Item.ENVELOPE);
+        fp.add(FetchProfile.Item.FLAGS);
+        fp.add(FetchProfile.Item.CONTENT_INFO);
+        folder.fetch(messages, fp);
+        
+        // loop over the fetched messages
+        for (int i = 0; i < messages.length && i < offset; i++) {
+            org.apache.hupa.shared.data.Message msg = new org.apache.hupa.shared.data.Message();
+            Message m = messages[i];                
+            String from = null;
+            if (m.getFrom() != null && m.getFrom().length >0 ) {
+                from = m.getFrom()[0].toString().trim();
+                try {
+                    from = MimeUtility.decodeText(from);
+                    userPreferences.addContact(from);
+                } catch (UnsupportedEncodingException e) {
+                    logger.debug("Unable to decode from " + from + " " + e.getMessage());
+                }
+            }
+            msg.setFrom(from);
+
+            String replyto = null;
+            if (m.getReplyTo() != null && m.getReplyTo().length >0 ) {
+                replyto = m.getReplyTo()[0].toString().trim();
+                try {
+                    replyto = MimeUtility.decodeText(replyto);
+                    userPreferences.addContact(replyto);
+                } catch (UnsupportedEncodingException e) {
+                    logger.debug("Unable to decode replyto " + replyto + " " + e.getMessage());
+                }
+            }
+            msg.setReplyto(replyto);
+            
+            ArrayList<String> to = new ArrayList<String>();
+            // Add to addresses
+            Address[] toArray = m.getRecipients(RecipientType.TO);
+            if (toArray != null) {
+                for (Address addr : toArray) {
+                    String mailTo = null;
+                    try {
+                        mailTo = MimeUtility.decodeText(addr.toString());
+                        userPreferences.addContact(mailTo);
+                    } catch (UnsupportedEncodingException e) {
+                        logger.debug("Unable to decode mailTo " + mailTo + " " + e.getMessage());
+                    }
+                    if (mailTo != null)
+                        to.add(mailTo);
+                }
+            }
+            msg.setTo(to);
+            
+            // Check if a subject exist and if so decode it
+            String subject = m.getSubject();
+            if (subject != null) {
+                try {
+                    subject = MimeUtility.decodeText(subject);
+                } catch (UnsupportedEncodingException e) {
+                    logger.debug("Unable to decode subject " + subject + " " + e.getMessage());
+                }
+            }
+            msg.setSubject(subject);
+            
+            // Add cc addresses
+            Address[] ccArray = m.getRecipients(RecipientType.CC);
+            ArrayList<String> cc = new ArrayList<String>();
+            if (ccArray != null) {
+                for (Address addr : ccArray) {
+                    String mailCc = null;
+                    try {
+                    	mailCc = MimeUtility.decodeText(addr.toString());
+                        userPreferences.addContact(mailCc);
+                    } catch (UnsupportedEncodingException e) {
+                        logger.debug("Unable to decode mailTo " + mailCc + " " + e.getMessage());
+                    }
+                    if (mailCc != null)
+                        cc.add(mailCc);
+                }            	
+            }
+            msg.setCc(cc);
+
+            // Using sentDate since received date is not useful in the view when using fetchmail
+            msg.setReceivedDate(m.getSentDate());
+
+            // Add flags
+            ArrayList<IMAPFlag> iFlags = JavamailUtil.convert(m.getFlags());
+          
+            ArrayList<Tag> tags = new ArrayList<Tag>();
+            for (String flag : m.getFlags().getUserFlags()) {
+                if (flag.startsWith(Tag.PREFIX)) {
+                    tags.add(new Tag(flag.substring(Tag.PREFIX.length())));
+                }
+            }
+            
+            msg.setUid(folder.getUID(m));
+            msg.setFlags(iFlags);
+            msg.setTags(tags);
+            try {
+                msg.setHasAttachments(hasAttachment(m));
+            } catch (MessagingException e) {
+                logger.debug("Unable to identify attachments in message UID:" + msg.getUid() + " subject:" + msg.getSubject() + " cause:" + e.getMessage());
+                logger.info("");
+            }
+            mList.add(0, msg);
+            
+        }
+        return mList;
+    }
+
+    private boolean hasAttachment(Message message) throws MessagingException {
+        if (message.getContentType().startsWith("multipart/")) {
+            try {
+                Object content;
+
+                content = message.getContent();
+
+                if (content instanceof Multipart) {
+                    Multipart mp = (Multipart) content;
+                    if (mp.getCount() > 1) {
+                        for (int i = 0; i < mp.getCount(); i++) {
+                            String disp = mp.getBodyPart(i).getDisposition();
+                            if (disp != null
+                                    && disp.equalsIgnoreCase(Part.ATTACHMENT)) {
+                                return true;
+                            }
+                        }
+                    }
+
+                }
+            } catch (IOException e) {
+                logger.error("Error while get content of message " + message.getMessageNumber());
+            }
+            
+        }
+        return false;
+    }
+    
+    
+    protected final class MessageConvertArray {
+        private Message[] messages;
+        private int realCount;
+
+        public MessageConvertArray(int realCount, Message[] messages) {
+            this.messages = messages;
+            this.realCount = realCount;
+        }
+        
+        public int getRealCount() {
+            return realCount;
+        }
+        
+        public Message[] getMesssages() {
+            return messages;
+        }
+    }
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSendMessageHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSendMessageHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSendMessageHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSendMessageHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,427 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.activation.DataSource;
+import javax.mail.Address;
+import javax.mail.AuthenticationFailedException;
+import javax.mail.BodyPart;
+import javax.mail.Flags.Flag;
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMessage.RecipientType;
+import javax.mail.internet.MimeMultipart;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.FileItemRegistry;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.server.preferences.UserPreferencesStorage;
+import org.apache.hupa.server.utils.MessageUtils;
+import org.apache.hupa.server.utils.RegexPatterns;
+import org.apache.hupa.server.utils.SessionUtils;
+import org.apache.hupa.shared.data.MessageAttachment;
+import org.apache.hupa.shared.data.SMTPMessage;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.GenericResult;
+import org.apache.hupa.shared.rpc.SendMessage;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.name.Named;
+import com.sun.mail.imap.IMAPFolder;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Handle sending of email messages
+ * 
+ */
+public abstract class AbstractSendMessageHandler<A extends SendMessage> extends AbstractSessionHandler<A,GenericResult> {
+
+    private final boolean auth;
+    private final String address;
+    private final int port;
+    private boolean useSSL = false;
+    UserPreferencesStorage userPreferences;
+    Session session;
+
+    @Inject
+    public AbstractSendMessageHandler(Log logger, IMAPStoreCache store, Provider<HttpSession> provider, UserPreferencesStorage preferences, @Named("SMTPServerAddress") String address, @Named("SMTPServerPort") int port, @Named("SMTPAuth") boolean auth, @Named("SMTPS") boolean useSSL) {
+        super(store,logger,provider);
+        this.auth = auth;
+        this.address = address;
+        this.port = port;
+        this.useSSL  = useSSL;
+        this.userPreferences = preferences;
+        this.session = store.getMailSession();
+        session.getProperties().put("mail.smtp.auth", auth);
+    }
+
+    @Override
+    protected GenericResult executeInternal(A action, ExecutionContext context)
+            throws ActionException {
+        GenericResult result = new GenericResult();
+        try {
+
+            Message message = createMessage(session, action);
+            message = fillBody(message,action);
+
+            sendMessage(getUser(), message);
+            saveSentMessage(getUser(), message);
+        
+            resetAttachments(action);
+        
+            // TODO: notify the user more accurately where the error is
+            // if the message was sent and the storage in the sent folder failed, etc.
+        } catch (AddressException e) {
+            result.setError("Error while parsing recipient: " + e.getMessage());
+            logger.error("Error while parsing recipient", e);
+        } catch (AuthenticationFailedException e) {
+            result.setError("Error while sending message: SMTP Authentication error.");
+            logger.error("SMTP Authentication error", e);
+        } catch (MessagingException e) {
+            result.setError("Error while sending message: " + e.getMessage());
+            logger.error("Error while sending message", e);
+        } catch (Exception e) {
+            result.setError("Unexpected exception while sendig message: " + e.getMessage());
+            logger.error("Unexpected exception while sendig message: ", e);
+        }
+        return result;
+    }
+    
+    /**
+     * Create basic Message which contains all headers. No body is filled
+     * 
+     * @param session the Session
+     * @param action the action
+     * @return message
+     * @throws AddressException
+     * @throws MessagingException
+     * @throws ActionException
+     */
+    protected Message createMessage(Session session, A action) throws AddressException, MessagingException {
+        MimeMessage message = new MimeMessage(session);
+        SMTPMessage m = action.getMessage();
+        message.setFrom(new InternetAddress(m.getFrom()));
+
+        userPreferences.addContact(m.getTo());
+        userPreferences.addContact(m.getCc());
+        userPreferences.addContact(m.getBcc());
+
+        message.setRecipients(RecipientType.TO, MessageUtils.getRecipients(m.getTo()));
+        message.setRecipients(RecipientType.CC, MessageUtils.getRecipients(m.getCc()));
+        message.setRecipients(RecipientType.BCC, MessageUtils.getRecipients(m.getBcc()));
+        message.setSubject(m.getSubject());
+        message.saveChanges();
+        return message;
+    }
+    /**
+     * Fill the body of the given message with data which the given action contain
+     * 
+     * @param message the message
+     * @param action the action
+     * @return filledMessage
+     * @throws MessagingException
+     * @throws ActionException
+     * @throws IOException 
+     */
+    protected Message fillBody(Message message, A action) throws MessagingException, ActionException, IOException {
+
+        String html = restoreInlineLinks(action.getMessage().getText());
+        
+        // TODO: client sends the message as a html document right now, 
+        // the idea is that it should be sent in both formats because
+        // it is easier to handle html in the browser. 
+        String text = htmlToText(html);
+        
+        @SuppressWarnings("rawtypes")
+        List items = getAttachments(action);
+        
+        return composeMessage(message, text, html, items);
+    }
+
+    protected String restoreInlineLinks(String s) {
+        return RegexPatterns.replaceAll(s, RegexPatterns.regex_revertInlineImg, RegexPatterns.repl_revertInlineImg);
+    }
+    
+    // TODO: just temporary stuff because it has to be done in the client side
+    protected String htmlToText(String s){
+        s=s.replaceAll("\n", " ");
+        s=s.replaceAll("(?si)<br\\s*?/?>", "\n");
+        s=s.replaceAll("(?si)</div\\s*?>", "\n");
+        s=s.replaceAll("(\\w)<.*?>(\\w)", "$1 $2");
+        s=s.replaceAll("<.*?>", "");
+        s=s.replaceAll("[ \t]+", " ");
+        return s;
+    }
+    
+    /**
+     * Get the attachments stored in the registry.
+     * 
+     * @param action
+     * @return A list of stored attachments
+     */
+    @SuppressWarnings("rawtypes")
+    protected List getAttachments(A action) throws MessagingException, ActionException {
+        FileItemRegistry registry = SessionUtils.getSessionRegistry(logger, httpSessionProvider.get());
+        List<MessageAttachment> attachments = action.getMessage().getMessageAttachments();
+        
+        ArrayList<FileItem> items = new ArrayList<FileItem>();
+        if (attachments != null && attachments.size() > 0) {
+            for (MessageAttachment attachment: attachments) {
+                FileItem fItem = registry.get(attachment.getName());
+                if (fItem != null)
+                    items.add(fItem);
+            }
+            logger.debug("Found " + items.size() + " attachmets in the registry.");
+        }
+        return items;
+    }
+    
+    /**
+     * Remove attachments from the registry
+     *  
+     * @param action
+     * @throws MessagingException
+     * @throws ActionException
+     */
+    protected void resetAttachments(A action) throws MessagingException, ActionException {
+        SMTPMessage msg = action.getMessage();
+        ArrayList<MessageAttachment> attachments = msg.getMessageAttachments();
+        if (attachments != null && ! attachments.isEmpty()) {
+            for(MessageAttachment attach : attachments) 
+                SessionUtils.getSessionRegistry(logger, httpSessionProvider.get()).remove(attach.getName());
+        }
+    }
+    
+    /**
+     * Send the message using SMTP, if the configuration uses authenticated SMTP, it uses
+     * the user stored in session to get the given login and password.
+     * 
+     * @param user
+     * @param session
+     * @param message
+     * @throws MessagingException
+     */
+    protected void sendMessage(User user, Message message) throws MessagingException {
+        
+        Transport transport = cache.getMailTransport(useSSL);
+    
+        if (auth) {
+            logger.debug("Use auth for smtp connection");
+            transport.connect(address,port,user.getName(), user.getPassword());
+        } else {
+            transport.connect(address, port, null,null);
+        }
+        
+        Address[] recips = message.getAllRecipients();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < recips.length; i++) {
+            sb.append(recips[i]);
+            if (i != recips.length -1) {
+                sb.append(", ");
+            }
+        }
+        logger.info("Send message from " + message.getFrom()[0].toString()+ " to " + sb.toString());
+        transport.sendMessage(message, recips);
+    }
+
+    /**
+     * Save the message in the sent folder
+     * 
+     * @param user
+     * @param message
+     * @throws MessagingException
+     * @throws IOException 
+     */
+    protected void saveSentMessage(User user, Message message) throws MessagingException, IOException {
+        IMAPStore iStore = cache.get(user);
+        IMAPFolder folder = (IMAPFolder) iStore.getFolder(user.getSettings().getSentFolderName());
+        
+        if (folder.exists() || folder.create(IMAPFolder.READ_WRITE)) {
+            if (folder.isOpen() == false) {
+                folder.open(Folder.READ_WRITE);
+            }
+
+            // It is necessary to copy the message, before putting it
+            // in the sent folder. If not, it is not guaranteed that it is 
+            // stored in ascii and is not possible to get the attachments
+            // size. message.saveChanges() doesn't fix the problem.
+            // There are tests which demonstrate this.
+            message = new MimeMessage((MimeMessage)message);
+
+            message.setFlag(Flag.SEEN, true);
+            folder.appendMessages(new Message[] {message});
+            
+            try {
+                folder.close(false);
+            } catch (MessagingException e) {
+                // we don't care on close
+            }
+        }
+    }
+
+    /**
+     * Fill the body of a message already created.
+     * The result message depends on the information given. 
+     * 
+     * @param message
+     * @param text
+     * @param html
+     * @param parts
+     * @return The composed message
+     * @throws MessagingException
+     * @throws IOException
+     */
+    @SuppressWarnings("rawtypes")
+    public static Message composeMessage (Message message, String text, String html, List parts) throws MessagingException, IOException {
+
+        MimeBodyPart txtPart = null;
+        MimeBodyPart htmlPart = null;
+        MimeMultipart mimeMultipart = null;
+
+        if (text == null && html == null) {
+           text = ""; 
+        }
+        if (text != null) {
+            txtPart = new MimeBodyPart();
+            txtPart.setContent(text, "text/plain");
+        }
+        if (html != null) {
+            htmlPart = new MimeBodyPart();
+            htmlPart.setContent(html, "text/html");
+        }
+        if (html != null && text != null) {
+            mimeMultipart = new MimeMultipart();
+            mimeMultipart.setSubType("alternative");
+            mimeMultipart.addBodyPart(txtPart);
+            mimeMultipart.addBodyPart(htmlPart);
+        }
+
+        if (parts == null || parts.isEmpty()) {
+            if (mimeMultipart != null) {
+                message.setContent(mimeMultipart);
+            } else if (html != null) {
+                message.setText(html);
+                message.setHeader("Content-type", "text/html");
+            } else if (text != null) {
+                message.setText(text);
+            }
+        } else {
+            MimeBodyPart bodyPart = new MimeBodyPart();
+            if (mimeMultipart != null) {
+                bodyPart.setContent(mimeMultipart);
+            } else if (html != null) {
+                bodyPart.setText(html);
+                bodyPart.setHeader("Content-type", "text/html");
+            } else if (text != null) {
+                bodyPart.setText(text);
+            }
+            Multipart multipart = new MimeMultipart();
+            multipart.addBodyPart(bodyPart);
+            for (Object attachment: parts) {
+                if (attachment instanceof FileItem) {
+                    multipart.addBodyPart(MessageUtils.fileitemToBodypart((FileItem)attachment));
+                } else {
+                    multipart.addBodyPart((BodyPart)attachment);
+                }
+            }
+            message.setContent(multipart);
+        }
+
+        message.saveChanges();
+        return message;
+
+    }
+    
+    /**
+     * DataStore which wrap a FileItem
+     * 
+     */
+    public static class FileItemDataStore implements DataSource {
+
+        private FileItem item;
+
+        public FileItemDataStore(FileItem item) {
+            this.item = item;
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see javax.activation.DataSource#getContentType()
+         */
+        public String getContentType() {
+            return item.getContentType();
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see javax.activation.DataSource#getInputStream()
+         */
+        public InputStream getInputStream() throws IOException {
+            return item.getInputStream();
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see javax.activation.DataSource#getName()
+         */
+        public String getName() {
+            String fullName = item.getName();
+            
+            // Strip path from file
+            int index = fullName.lastIndexOf(File.separator);
+            if (index == -1) {
+                return fullName;
+            } else {
+                return fullName.substring(index +1 ,fullName.length());
+            }
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see javax.activation.DataSource#getOutputStream()
+         */
+        public OutputStream getOutputStream() throws IOException {
+            return null;
+        }
+
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSessionHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSessionHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSessionHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/AbstractSessionHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,92 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+
+package org.apache.hupa.server.handler;
+
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ActionHandler;
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.Action;
+import net.customware.gwt.dispatch.shared.ActionException;
+import net.customware.gwt.dispatch.shared.Result;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.SConsts;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.exception.InvalidSessionException;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+/**
+ * Abstract class which take care of checking if the session is still valid before
+ * executing the handler
+ * 
+ */
+public abstract class AbstractSessionHandler<A extends Action<R>,R extends Result> implements ActionHandler<A, R> {
+
+    protected final Provider<HttpSession> httpSessionProvider;
+    protected final IMAPStoreCache cache;
+    protected final Log logger;
+
+    @Inject
+    public AbstractSessionHandler(IMAPStoreCache cache, Log logger, Provider<HttpSession> httpSessionProvider) {
+        this.httpSessionProvider = httpSessionProvider;
+        this.cache = cache;
+        this.logger = logger;
+    }
+
+    /**
+     * Execute executeInternal method
+     */
+    public R execute(A action, ExecutionContext context) throws ActionException {
+        return executeInternal(action, context);
+    }
+    
+    /**
+     * Not implemented. Should get overridden if needed
+     */
+    public void rollback(A action, R result,
+            ExecutionContext context) throws ActionException {
+        // Not implemented
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see net.customware.gwt.dispatch.server.ActionHandler#execute(net.customware.gwt.dispatch.shared.Action, net.customware.gwt.dispatch.server.ExecutionContext)
+     */
+    protected abstract R executeInternal(A action, ExecutionContext context) throws ActionException;
+    
+    /**
+     * Return the User stored in session with the given id
+     * 
+     * @return user
+     * @throws ActionException
+     */
+    protected User getUser() throws ActionException{
+        User user = (User) httpSessionProvider.get().getAttribute(SConsts.USER_SESS_ATTR);
+        if (user == null) {
+            throw new InvalidSessionException("User not found in session with id " + httpSessionProvider.get().getId());
+        } else {
+            return user;
+        }
+    }
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CheckSessionHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CheckSessionHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CheckSessionHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CheckSessionHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,72 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+
+package org.apache.hupa.server.handler;
+
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ActionHandler;
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.CheckSession;
+import org.apache.hupa.shared.rpc.CheckSessionResult;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+/**
+ * Handler for asking the server if the session is valid
+ */
+public class CheckSessionHandler implements ActionHandler<CheckSession, CheckSessionResult> {
+    
+    protected final Provider<HttpSession> sessionProvider;
+    protected final Log logger;
+    
+    @Inject
+    public CheckSessionHandler(Log logger, Provider<HttpSession> provider) {
+        this.sessionProvider = provider;
+        this.logger = logger;
+    }
+
+    public CheckSessionResult execute(CheckSession arg0, ExecutionContext arg1) throws ActionException {
+        CheckSessionResult ret = new CheckSessionResult();
+        try {
+            User user = (User) sessionProvider.get().getAttribute("user");
+            if (user != null && user.getAuthenticated())
+                ret.setUser(user);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        logger.debug("CheckSession returns: " + ret.isValid());
+        return ret;
+    }
+
+    public Class<CheckSession> getActionType() {
+        return CheckSession.class;
+    }
+
+    public void rollback(CheckSession arg0, CheckSessionResult arg1, ExecutionContext arg2) throws ActionException {
+    }
+
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ContactsHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ContactsHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ContactsHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ContactsHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,60 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import net.customware.gwt.dispatch.server.ActionHandler;
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.server.preferences.UserPreferencesStorage;
+import org.apache.hupa.shared.rpc.Contacts;
+import org.apache.hupa.shared.rpc.ContactsResult;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * Handler for getting the list of contacts
+ */
+public class ContactsHandler implements ActionHandler<Contacts, ContactsResult> {
+
+    UserPreferencesStorage userPreferences;
+
+    @Inject
+    public ContactsHandler(IMAPStoreCache cache, Log logger, Provider<HttpSession> sessionProvider, UserPreferencesStorage preferences) {
+        this.userPreferences = preferences;
+    }
+
+    public ContactsResult execute(Contacts action, ExecutionContext context) throws ActionException {
+        return new ContactsResult(userPreferences.getContacts());
+    }
+
+    public Class<Contacts> getActionType() {
+        return Contacts.class;
+    }
+
+    public void rollback(Contacts action, ContactsResult result, ExecutionContext context) throws ActionException {
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CreateFolderHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CreateFolderHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CreateFolderHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/CreateFolderHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,83 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import javax.mail.Folder;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.data.IMAPFolder;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.CreateFolder;
+import org.apache.hupa.shared.rpc.GenericResult;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Handle creation of folders
+ * 
+ *
+ */
+public class CreateFolderHandler extends AbstractSessionHandler<CreateFolder, GenericResult>{
+
+    @Inject
+    public CreateFolderHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> sessionProvider) {
+        super(cache, logger, sessionProvider);
+    }
+
+    @Override
+    protected GenericResult executeInternal(CreateFolder action,
+            ExecutionContext context) throws ActionException {
+        User user = getUser();
+        IMAPFolder folder = action.getFolder();
+        
+        try {
+            IMAPStore store = cache.get(user);
+            Folder f = store.getFolder(folder.getFullName());
+            if (f.create(Folder.HOLDS_MESSAGES)) {
+                logger.info("Successfully create folder " + folder + " for user " + user);
+                return new GenericResult();
+            } else {
+                logger.info("Unable to create folder " + folder + " for user " + user);
+                throw new ActionException("Unable to create folder " + folder + " for user " + user);
+
+            }
+        } catch (Exception e) {
+            logger.error("Error while creating folder " + folder + " for user " + user, e);
+            throw new ActionException("Error while creating folder " + folder + " for user " + user, e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<CreateFolder> getActionType() {
+        return CreateFolder.class;
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteAllMessagesHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteAllMessagesHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteAllMessagesHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteAllMessagesHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,79 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.DeleteAllMessages;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.sun.mail.imap.IMAPFolder;
+import com.sun.mail.imap.IMAPStore;
+
+public class DeleteAllMessagesHandler extends AbstractDeleteMessageHandler<DeleteAllMessages>{
+
+    @Inject
+    public DeleteAllMessagesHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> sessionProvider) {
+        super(cache, logger, sessionProvider);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.hupa.server.handler.AbstractDeleteMessageHandler#getMessagesToDelete(org.apache.hupa.shared.rpc.DeleteMessage)
+     */
+    protected Message[] getMessagesToDelete(DeleteAllMessages action)
+            throws ActionException {
+        User user = getUser();
+        try {
+            logger.info("Delete all messages in folder " + action.getFolder() + " for user " + user);
+            IMAPStore store =cache.get(user);
+            IMAPFolder folder = (IMAPFolder) store.getFolder(action.getFolder().getFullName());
+            if (folder.isOpen() == false) {
+                folder.open(Folder.READ_WRITE);
+            }
+            return folder.getMessages();
+        } catch (MessagingException e) {
+            String errorMsg = "Error while deleting all messages in folder " + action.getFolder() + " for user " + user;
+            logger.error(errorMsg, e);
+            throw new ActionException(errorMsg);
+
+        }
+        
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<DeleteAllMessages> getActionType() {
+        return DeleteAllMessages.class;
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteFolderHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteFolderHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteFolderHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteFolderHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,88 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import javax.mail.Folder;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.data.IMAPFolder;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.DeleteFolder;
+import org.apache.hupa.shared.rpc.GenericResult;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Handle delete requests for a folder
+ * 
+ *
+ */
+public class DeleteFolderHandler extends AbstractSessionHandler<DeleteFolder, GenericResult>{
+
+    @Inject
+    public DeleteFolderHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> sessionProvider) {
+        super(cache, logger, sessionProvider);
+    }
+
+    @Override
+    protected GenericResult executeInternal(DeleteFolder action,
+            ExecutionContext context) throws ActionException {
+        User user = getUser();
+        IMAPFolder folder = action.getFolder();
+        try {
+            IMAPStore store = cache.get(user);
+            
+            Folder f = store.getFolder(folder.getFullName());
+            
+            // close the folder if its open
+            if (f.isOpen()) {
+                f.close(false);
+            }
+            
+            // recursive delete the folder
+            if (f.delete(true)) {
+                logger.info("Successfully delete folder " + folder + " for user " + user);
+                return new GenericResult();
+            } else {
+                throw new ActionException("Unable to delete folder " + folder + " for user " + user);
+            }
+        } catch (Exception e) {
+            logger.error("Error while deleting folder " + folder + " for user " + user,e);
+            throw new ActionException("Error while deleting folder " + folder + " for user " + user,e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<DeleteFolder> getActionType() {
+        return DeleteFolder.class;
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteMessageByUidHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteMessageByUidHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteMessageByUidHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/DeleteMessageByUidHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,96 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.data.IMAPFolder;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.DeleteMessageByUid;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Handler which take care of deleting messages
+ * 
+ */
+public class DeleteMessageByUidHandler extends
+        AbstractDeleteMessageHandler<DeleteMessageByUid> {
+
+    @Inject
+    public DeleteMessageByUidHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> provider) {
+        super(cache, logger, provider);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<DeleteMessageByUid> getActionType() {
+        return DeleteMessageByUid.class;
+    }
+
+    @Override
+    protected Message[] getMessagesToDelete(DeleteMessageByUid action)
+            throws ActionException {
+        IMAPFolder folder = action.getFolder();
+        ArrayList<Long> uids = action.getMessageUids();
+        User user = getUser();
+
+        logger.info("Deleting messages with uids " + action.getMessageUids()
+                + " for user " + user + " in folder " + action.getFolder());
+        try {
+            IMAPStore store = cache.get(user);
+            com.sun.mail.imap.IMAPFolder f = (com.sun.mail.imap.IMAPFolder) store
+                    .getFolder(folder.getFullName());
+            // check if the folder is open, if not open it "rw"
+            if (f.isOpen() == false) {
+                f.open(com.sun.mail.imap.IMAPFolder.READ_WRITE);
+            }
+            // build up the list of messages to delete
+            List<Message> messages = new ArrayList<Message>();
+            for (Long uid : uids) {
+                messages.add(f.getMessageByUID(uid));
+            }
+            Message[] mArray = messages.toArray(new Message[messages.size()]);
+            return mArray;
+        } catch (MessagingException e) {
+            logger.error("Error while deleting messages with uids "
+                    + action.getMessageUids() + " for user " + user
+                    + " in folder" + action.getFolder(), e);
+            throw new ActionException("Error while deleting messages", e);
+        }
+
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchFoldersHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchFoldersHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchFoldersHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchFoldersHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,144 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.mail.Folder;
+import javax.mail.MessagingException;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.shared.data.IMAPFolder;
+import org.apache.hupa.shared.data.User;
+import org.apache.hupa.shared.rpc.FetchFolders;
+import org.apache.hupa.shared.rpc.FetchFoldersResult;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Handler which fetch all Folders for an user
+ * 
+ */
+public class FetchFoldersHandler extends AbstractSessionHandler<FetchFolders, FetchFoldersResult>{
+
+    @Inject
+    public FetchFoldersHandler(IMAPStoreCache cache, Log logger,Provider<HttpSession> provider) {
+        super(cache,logger,provider);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.hupa.server.handler.AbstractSessionHandler#executeInternal(org.apache.hupa.shared.rpc.Session, net.customware.gwt.dispatch.server.ExecutionContext)
+     */
+    public FetchFoldersResult executeInternal(FetchFolders action, ExecutionContext arg1)
+    throws ActionException {
+        User user = getUser();
+        try {
+
+            // get the store for the user
+            IMAPStore store = cache.get(user);
+            com.sun.mail.imap.IMAPFolder folder = (com.sun.mail.imap.IMAPFolder) store.getDefaultFolder();
+            
+            // List of mail 'root' imap folders
+            List<IMAPFolder> imapFolders = new ArrayList<IMAPFolder>();
+
+            // Create IMAPFolder tree list
+            for (Folder f : folder.list()) {
+                IMAPFolder imapFolder = createIMAPFolder(f);
+                imapFolders.add(imapFolder);
+                walkFolders(f, imapFolder);
+            }
+            
+            // Create the tree and return the result
+            FetchFoldersResult fetchFolderResult = new FetchFoldersResult(imapFolders);
+            logger.debug("Fetching folders for user: " + user + " returns:\n" + fetchFolderResult.toString());
+
+            return fetchFolderResult;
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error("Unable to get folders for User " + user,e);
+            throw new ActionException("Unable to get folders for User "
+                    + user);
+        }
+    }
+
+    /**
+     * Walk through the folder's sub-folders and add sub-folders to current imapFolder
+     *   
+     * @param folder Folder to walk
+     * @param imapFolder Current IMAPFolder
+     * @throws ActionException If an error occurs
+     * @throws MessagingException If an error occurs
+     */
+    private void walkFolders(Folder folder, IMAPFolder imapFolder) throws ActionException, MessagingException{
+        for (Folder f : folder.list()) {
+            IMAPFolder iFolder = createIMAPFolder(f);
+            imapFolder.getChildIMAPFolders().add(iFolder);
+            walkFolders(f, iFolder);
+        }
+    }
+    /*
+     * (non-Javadoc)
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<FetchFolders> getActionType() {
+        return FetchFolders.class;
+    }
+
+    /**
+     * Create a new IMAPFolder from the given Folder
+     * 
+     * @param folder Current folder
+     * @return imapFolder Created IMAPFolder
+     * @throws ActionException If an error occurs
+     * @throws MessagingException If an error occurs
+     */
+    private IMAPFolder createIMAPFolder(Folder folder) throws ActionException {
+
+        String fullName = folder.getFullName();
+        String delimiter;
+        IMAPFolder iFolder = null;
+        
+        try {
+            logger.debug("Creating folder: " + fullName + " for user: " + getUser());
+            delimiter = String.valueOf(folder.getSeparator());
+            iFolder = new IMAPFolder(fullName);
+            iFolder.setDelimiter(delimiter);
+            if("[Gmail]".equals(folder.getFullName()))
+                return iFolder;
+            iFolder.setMessageCount(folder.getMessageCount());
+            iFolder.setSubscribed(folder.isSubscribed());
+            iFolder.setUnseenMessageCount(folder.getUnreadMessageCount());
+        } catch (MessagingException e) {
+            logger.error("Unable to construct folder " + folder.getFullName(),e);
+        }
+        
+        return iFolder;
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchMessagesHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchMessagesHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchMessagesHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchMessagesHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,122 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.search.BodyTerm;
+import javax.mail.search.FromStringTerm;
+import javax.mail.search.OrTerm;
+import javax.mail.search.SearchTerm;
+import javax.mail.search.SubjectTerm;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.server.preferences.UserPreferencesStorage;
+import org.apache.hupa.shared.rpc.FetchMessages;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+/**
+ * Fetch Messages for a user. The Messages don't contain any body, just some
+ * fields of the headers are fetched for perfomance reasons
+ * 
+ */
+public class FetchMessagesHandler extends
+        AbstractFetchMessagesHandler<FetchMessages> {
+    
+
+    @Inject
+    public FetchMessagesHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> provider, UserPreferencesStorage preferences) {
+        super(cache, logger, provider, preferences);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<FetchMessages> getActionType() {
+        return FetchMessages.class;
+    }
+
+    @Override
+    protected MessageConvertArray getMessagesToConvert(com.sun.mail.imap.IMAPFolder f,
+            FetchMessages action) throws MessagingException, ActionException {
+        String searchString = action.getSearchString();
+        int start = action.getStart();
+        int offset = action.getOffset();
+        int end = start + offset;
+        Message[] messages;
+        int exists;
+        // check if a searchString was given, and if so use it
+        if (searchString == null) {
+            exists = f.getMessageCount();
+
+            if (end > exists) {
+                end = exists;
+            }
+
+            int firstIndex = exists - end + 1;
+            if (firstIndex < 1) {
+                firstIndex = 1;
+            }
+            int lastIndex = exists - start;
+            
+            messages = f.getMessages(firstIndex, lastIndex);
+        } else {
+            SearchTerm subjectTerm = new SubjectTerm(searchString);
+            SearchTerm fromTerm = new FromStringTerm(searchString);
+            SearchTerm bodyTerm = new BodyTerm(searchString);
+            SearchTerm orTerm = new OrTerm(new SearchTerm[] { subjectTerm,
+                    fromTerm, bodyTerm });
+            Message[] tmpMessages = f.search(orTerm);
+            if (end > tmpMessages.length) {
+                end = tmpMessages.length;
+            }
+            exists = tmpMessages.length;
+
+            int firstIndex = exists - end;        
+            
+            if (tmpMessages.length > firstIndex) {
+                List<Message> mList = new ArrayList<Message>();
+                for (int i = firstIndex; i < tmpMessages.length; i++) {
+                    if (i == end) break;
+                    mList.add(tmpMessages[i]);
+                }
+                messages = mList.toArray(new Message[mList.size()]);
+            } else {
+                messages = new Message[0];
+            }
+          
+        }
+        logger.debug("Fetching messages for user: " + getUser() + " returns: " + messages.length + " messages in " + f.getFullName());
+
+        return new MessageConvertArray(exists, messages);
+    }
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchRecentMessagesHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchRecentMessagesHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchRecentMessagesHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/FetchRecentMessagesHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,62 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+
+package org.apache.hupa.server.handler;
+
+import javax.mail.Flags;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Flags.Flag;
+import javax.mail.search.FlagTerm;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.server.preferences.UserPreferencesStorage;
+import org.apache.hupa.shared.rpc.FetchRecentMessages;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class FetchRecentMessagesHandler extends AbstractFetchMessagesHandler<FetchRecentMessages> {
+
+    @Inject
+    public FetchRecentMessagesHandler(IMAPStoreCache cache, Log logger,
+            Provider<HttpSession> provider, UserPreferencesStorage preferences) {
+        super(cache, logger, provider, preferences);
+    }
+
+    
+    @Override
+    protected MessageConvertArray getMessagesToConvert(com.sun.mail.imap.IMAPFolder f,
+            FetchRecentMessages action) throws MessagingException {
+        Message[] messages = f.search(new FlagTerm(new Flags(Flag.RECENT), true));
+        return new MessageConvertArray(messages.length, messages);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<FetchRecentMessages> getActionType() {
+        return FetchRecentMessages.class;
+    }
+
+}

Added: james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ForwardMessageHandler.java
URL: http://svn.apache.org/viewvc/james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ForwardMessageHandler.java?rev=1516205&view=auto
==============================================================================
--- james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ForwardMessageHandler.java (added)
+++ james/hupa/trunk/server/src/main/java/org/apache/hupa/server/handler/ForwardMessageHandler.java Wed Aug 21 16:35:16 2013
@@ -0,0 +1,89 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.hupa.server.handler;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.servlet.http.HttpSession;
+
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.hupa.server.IMAPStoreCache;
+import org.apache.hupa.server.preferences.UserPreferencesStorage;
+import org.apache.hupa.server.utils.MessageUtils;
+import org.apache.hupa.shared.rpc.ForwardMessage;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.name.Named;
+import com.sun.mail.imap.IMAPFolder;
+import com.sun.mail.imap.IMAPStore;
+
+/**
+ * Handler which handles the forwarding of a message
+ * 
+ */
+public class ForwardMessageHandler extends AbstractSendMessageHandler<ForwardMessage> {
+
+    @Inject
+    public ForwardMessageHandler(Log logger, IMAPStoreCache store, Provider<HttpSession> provider, UserPreferencesStorage preferences, @Named("SMTPServerAddress") String address, @Named("SMTPServerPort") int port,
+            @Named("SMTPAuth") boolean auth, @Named("SMTPS") boolean useSSL) {
+        super(logger, store, provider, preferences, address, port, auth, useSSL);
+    }
+
+    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected List getAttachments(ForwardMessage action) throws MessagingException, ActionException {
+        List<?> items = new ArrayList();
+        IMAPStore store = cache.get(getUser());
+
+        IMAPFolder folder = (IMAPFolder) store.getFolder(action.getFolder().getFullName());
+        if (folder.isOpen() == false) {
+            folder.open(Folder.READ_ONLY);
+        }
+        // Put the original attachments in the list 
+        Message msg = folder.getMessageByUID(action.getReplyMessageUid());
+        try {
+            items = MessageUtils.extractMessageAttachments(logger, msg.getContent());
+            logger.debug("Forwarding a message, extracted: " + items.size() + " from original.");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        // Put in the list the attachments uploaded by the user
+        items.addAll(super.getAttachments(action));
+        return items;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see net.customware.gwt.dispatch.server.ActionHandler#getActionType()
+     */
+    public Class<ForwardMessage> getActionType() {
+        return ForwardMessage.class;
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org