001 /* 002 * Copyright 2010 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package com.hs.mail.sieve; 017 018 import java.io.IOException; 019 020 import javax.mail.MessagingException; 021 import javax.mail.internet.MimeMessage; 022 023 import org.apache.jsieve.mail.ActionFileInto; 024 import org.apache.jsieve.mail.ActionKeep; 025 import org.apache.jsieve.mail.ActionRedirect; 026 import org.apache.jsieve.mail.ActionReject; 027 028 import com.hs.mail.imap.ImapConstants; 029 import com.hs.mail.mailet.MailetContext; 030 import com.hs.mail.smtp.message.DeliveryStatusNotifier; 031 import com.hs.mail.smtp.message.MailAddress; 032 033 public class Actions { 034 035 /** 036 * Constructor for Actions. 037 */ 038 private Actions() { 039 super(); 040 } 041 042 /** 043 * <p> 044 * Executes the passed ActionFileInto. 045 * </p> 046 * 047 * <p> 048 * This implementation accepts any destination with the root of <code>INBOX</code>. 049 * </p> 050 * 051 * <p> 052 * As the current POP3 server does not support sub-folders, the mail is 053 * stored in the INBOX for the recipient of the mail and the full intended 054 * destination added as a prefix to the message's subject. 055 * </p> 056 * 057 * <p> 058 * When IMAP support is added to James, it will be possible to support 059 * sub-folders of <code>INBOX</code> fully. 060 * </p> 061 * 062 * @param anAction 063 * @param aMail 064 * @param aMailetContext 065 * @throws MessagingException 066 */ 067 public static void execute(ActionFileInto anAction, SieveMailAdapter aMail, 068 MailetContext aMailetContext) throws MessagingException { 069 boolean delivered = false; 070 try { 071 String destination = anAction.getDestination(); 072 aMailetContext.storeMail(aMail.getSoleRecipientID(), destination, 073 aMail.getMessage()); 074 delivered = true; 075 } catch (IOException e) { 076 throw new MessagingException(e.getMessage(), e); 077 } finally { 078 // Ensure the mail is always ghosted 079 } 080 if (delivered) { 081 } 082 } 083 084 /** 085 * <p> 086 * Executes the passed ActionKeep. 087 * </p> 088 * 089 * <p> 090 * In this implementation, "keep" is equivalent to "fileinto" with a 091 * destination of "INBOX". 092 * </p> 093 * 094 * @param anAction 095 * @param aMail 096 * @param aMailetContext 097 * @throws MessagingException 098 */ 099 public static void execute(ActionKeep anAction, SieveMailAdapter aMail, 100 MailetContext aMailetContext) throws MessagingException { 101 ActionFileInto action = new ActionFileInto(ImapConstants.INBOX_NAME); 102 execute(action, aMail, aMailetContext); 103 } 104 105 /** 106 * Method execute executes the passed ActionRedirect. 107 * 108 * @param anAction 109 * @param aMail 110 * @param aMailetContext 111 * @throws MessagingException 112 */ 113 public static void execute(ActionRedirect anAction, SieveMailAdapter aMail, 114 MailetContext aMailetContext) throws MessagingException { 115 try { 116 detectAndHandleLocalLooping(aMail, anAction.getAddress()); 117 aMailetContext.sendMail(aMail.getSoleRecipient(), 118 new String[] { anAction.getAddress() }, aMail.getMessage()); 119 } catch (IOException e) { 120 throw new MessagingException(e.getMessage(), e); 121 } 122 } 123 124 /** 125 * <p> 126 * Method execute executes the passed ActionReject. It sends an RFC 2098 127 * compliant reject MDN back to the sender. 128 * </p> 129 * 130 * @param anAction 131 * @param aMail 132 * @param aMailetContext 133 * @throws MessagingException 134 */ 135 public static void execute(ActionReject anAction, SieveMailAdapter aMail, 136 MailetContext aMailetContext) throws MessagingException { 137 detectAndHandleLocalLooping(aMail, null); 138 // Create the MDN part 139 StringBuilder humanText = new StringBuilder(128); 140 humanText.append("This message was refused by the recipient's mail filtering program."); 141 humanText.append("\r\n"); 142 humanText.append("The reason given was:"); 143 humanText.append("\r\n"); 144 humanText.append("\r\n"); 145 humanText.append(anAction.getMessage()); 146 147 MimeMessage message = aMail.getMessage().getMimeMessage(); 148 DeliveryStatusNotifier.dsnNotify(aMail.getSoleRecipient(), 149 new MailAddress(message.getReplyTo()[0]), message, 150 humanText.toString()); 151 } 152 153 /** 154 * Detect and handle locally looping mail. External loop detection is left 155 * to the MTA. 156 * 157 * @param aMail 158 * @param aMailetContext 159 * @param anAttributeSuffix 160 * @throws MessagingException 161 */ 162 protected static void detectAndHandleLocalLooping(SieveMailAdapter aMail, 163 String recipient) throws MessagingException { 164 if (aMail.getMessage().isNotificationMessage()) { 165 // Don't reject or redirect notification message. 166 throw new MessagingException( 167 "This message is a notification message!"); 168 } 169 try { 170 String from = getSender(aMail); 171 if (from != null && from.equals(recipient)) { 172 MessagingException ex = new MessagingException( 173 "This message is looping!"); 174 throw ex; 175 } 176 } catch (IOException e) { 177 throw new MessagingException(e.getMessage(), e); 178 } 179 } 180 181 private static String getSender(SieveMailAdapter aMail) throws IOException { 182 return aMail.getMessage().getMailMessage().getFrom(); 183 } 184 185 }