1 21 package org.jsmtpd.plugins.deliveryServices; 22 23 import java.io.File ; 24 import java.io.FileNotFoundException ; 25 import java.io.IOException ; 26 import java.io.RandomAccessFile ; 27 import java.nio.channels.FileChannel ; 28 import java.nio.channels.FileLock ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 import java.util.List ; 32 import java.util.Map ; 33 34 import org.apache.commons.logging.Log; 35 import org.apache.commons.logging.LogFactory; 36 import org.jsmtpd.core.common.PluginInitException; 37 import org.jsmtpd.core.common.delivery.FatalDeliveryException; 38 import org.jsmtpd.core.common.delivery.IDeliveryService; 39 import org.jsmtpd.core.common.delivery.TemporaryDeliveryException; 40 import org.jsmtpd.core.common.io.InvalidStreamParserInitialisation; 41 import org.jsmtpd.core.common.io.dataStream.DataStreamParser; 42 import org.jsmtpd.core.mail.Email; 43 import org.jsmtpd.core.mail.EmailAddress; 44 import org.jsmtpd.core.mail.Rcpt; 45 import org.jsmtpd.tools.ByteArrayTool; 46 import org.jsmtpd.tools.DateUtil; 47 import org.jsmtpd.tools.rights.IChown; 48 import org.jsmtpd.tools.rights.RightException; 49 import org.jsmtpd.tools.rights.UnixChown; 50 51 57 public class UnixMailboxWriter implements IDeliveryService { 58 private Log log = LogFactory.getLog(UnixMailboxWriter.class); 59 private String mailboxDir = null; 60 private Map <String ,FileLock > locks = Collections.synchronizedMap(new HashMap <String ,FileLock >()); 61 private boolean tryChown = false; 62 private IChown chown = new UnixChown(); 63 64 public void setTryChown(boolean tryChown) { 65 this.tryChown = tryChown; 66 } 67 68 public void doDelivery(Email in, List <Rcpt> rcpts) { 69 log.debug("Begin "); 70 for (Rcpt rcpt : rcpts) { 71 try { 72 doSingleDelivery(in,rcpt.getEmailAddress()); 73 rcpt.setDelivered(Rcpt.STATUS_DELIVERED); 74 } catch (FatalDeliveryException e) { 75 rcpt.setDelivered(Rcpt.STATUS_ERROR_FATAL); 76 } catch (TemporaryDeliveryException e) { 77 rcpt.setDelivered(Rcpt.STATUS_ERROR_NOT_FATAL); 78 } 79 } 80 log.debug("end"); 81 } 82 83 90 public void doSingleDelivery(Email in, EmailAddress rcpt) throws FatalDeliveryException, TemporaryDeliveryException { 91 RandomAccessFile fp = null; 92 String mailbox = mailboxDir + "/" + rcpt.getUser().toLowerCase(); 93 boolean exist = new File (mailbox).exists(); 94 try { 95 fp = openMBox(mailbox); 96 log.debug("Locked mailbox: " + rcpt.getUser()); 98 fp.seek(fp.length()); 99 try { 100 DataStreamParser dsp = new DataStreamParser(512, 512); 101 dsp.appendString("From " + in.getFrom().toString() + " " + DateUtil.currentMailboxDate()); 102 fp.write(ByteArrayTool.replaceBytes(dsp.getData(), ByteArrayTool.CRLF, ByteArrayTool.LF)); 103 } catch (InvalidStreamParserInitialisation e1) { 104 } 105 106 byte[] pattern = { '\n', 'F', 'r', 'o', 'm', ' ' }; 107 byte[] replace = { '\n', '>', 'F', 'r', 'o', 'm', ' ' }; 108 byte[] tempo = ByteArrayTool.replaceBytes(in.getDataAsByte(), ByteArrayTool.CRLF, ByteArrayTool.LF); 110 tempo = ByteArrayTool.replaceBytes(tempo, pattern, replace); 112 fp.write(tempo); 113 114 byte[] lf = new byte[1]; 116 lf[0] = 10; 117 fp.write(lf); 118 if ((!exist) && tryChown) 119 chown.chown(mailbox,rcpt.getUser().toLowerCase()); 120 log.debug("Mail "+in.getDiskName()+ " delivered to : " + rcpt.getUser()); 122 } 123 124 catch (TemporaryDeliveryException tde) { 125 log.info("Could not open/lock local mailbox: " + rcpt.getUser() + ", delivery delayed"); 126 throw tde; 127 } 128 129 catch (IOException e) { 130 log.info("IO Error delivering mail from " + in.getFrom().toString() + " to mailbox " + rcpt.toString() 132 + ", mail to this rcpt is lost",e); 133 throw new FatalDeliveryException(); 134 } catch (RightException e) { 135 log.error("Things are written, but I could not perfom chown on file ...",e); 136 } finally { 137 closeMBox(mailbox,fp); 138 } 139 } 140 141 private void goSleep() { 142 try { 143 Thread.sleep(1000); 144 } catch (InterruptedException e) { 145 } 146 } 147 148 public String getPluginName() { 149 return "UnixMailboxWriter plugin for jsmtpd"; 150 } 151 152 157 public void initPlugin() throws PluginInitException { 158 159 } 160 161 164 public void shutdownPlugin() { 165 166 } 167 168 public void setMailDir(String mailboxesDirectory) { 170 this.mailboxDir = mailboxesDirectory; 171 } 172 178 private synchronized RandomAccessFile openMBox (String fileName) throws TemporaryDeliveryException { 179 RandomAccessFile target = null; 180 FileLock lock = null; 181 if (locks.containsKey(fileName)) 183 throw new TemporaryDeliveryException(); 184 else { 185 locks.put(fileName,null); 186 try { 187 target = getRandomAccessFile(fileName); 188 lock = getLock(target.getChannel(),fileName); 189 if (!lock.isValid()) { 190 throw new TemporaryDeliveryException(); 191 } 192 locks.put(fileName,lock); 193 } catch (TemporaryDeliveryException e) { 194 locks.remove(fileName); 195 throw e; 196 } 197 } 198 return target; 199 } 200 207 private FileLock getLock (FileChannel channel,String mbox) throws TemporaryDeliveryException { 208 FileLock lock = null; 209 int tryCount = 0; 210 while (lock == null) { 212 try { 213 lock = channel.tryLock(); 214 } catch (IOException e) { 215 lock=null; 216 } 217 if (lock == null) { 218 log.debug("Can't lock mailbox:"+mbox+" retrying"); 219 tryCount++; 220 goSleep(); 221 } 222 if (tryCount > 10) 223 throw new TemporaryDeliveryException(); 224 } 225 return lock; 226 } 227 233 private RandomAccessFile getRandomAccessFile (String mailbox) throws TemporaryDeliveryException { 235 RandomAccessFile fp = null; 236 int tryCount = 0; 237 while (fp == null) { 238 if (tryCount > 10) 239 throw new TemporaryDeliveryException(); 240 241 try { 242 tryCount++; 243 fp = new RandomAccessFile (mailbox, "rw"); 244 } catch (FileNotFoundException fileNotFoundException) { 245 log.debug("Can't open mailbox: "+mailbox+"retrying"); 246 } 247 if (fp == null) 248 goSleep(); 249 } 250 return fp; 251 } 252 253 private synchronized void closeMBox (String fileName,RandomAccessFile fp){ 254 if (locks.containsKey(fileName)) { 255 FileLock lock = locks.get(fileName); 256 locks.remove(fileName); 257 if (lock!= null) { 258 try { 259 lock.release(); 260 log.debug("UNlocked mailbox: " + fileName); 261 } catch (IOException e) { 262 log.error("Error Unlocking mailbox: " + fileName,e); 263 } 264 } else 265 log.error("Lock is not a file lock ?! "+lock); 266 } 267 if (fp != null) { 268 try { 269 fp.close(); 270 } catch (IOException e) { 271 log.error("Error closing File ",e); 272 } 273 } 274 } 275 } | Popular Tags |