1 19 package org.columba.mail.folder.mbox; 20 21 import java.io.File ; 22 import java.io.FileInputStream ; 23 import java.io.FileOutputStream ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.io.ObjectInputStream ; 27 import java.io.ObjectOutputStream ; 28 import java.io.RandomAccessFile ; 29 import java.nio.channels.FileChannel ; 30 import java.util.Enumeration ; 31 import java.util.Hashtable ; 32 import java.util.logging.Logger ; 33 34 import org.columba.core.io.StreamUtils; 35 import org.columba.mail.folder.AbstractMessageFolder; 36 import org.columba.mail.folder.FolderInconsistentException; 37 import org.columba.mail.folder.IDataStorage; 38 import org.columba.ristretto.io.FileSource; 39 import org.columba.ristretto.io.Source; 40 41 public class MboxDataStorage implements IDataStorage { 42 43 44 private static final Logger LOG = Logger 45 .getLogger("org.columba.mail.folder.mbox"); 46 47 private static final String FROMLINE = "From \n"; 48 49 private static final byte[] TERMLINE = new byte[] { '\n' }; 50 51 protected AbstractMessageFolder folder; 52 53 protected File mboxFile; 54 55 protected File messageFile; 56 57 protected Hashtable messages; 58 59 protected Object largestUid; 60 61 66 public MboxDataStorage(AbstractMessageFolder folder) { 67 this.folder = folder; 68 messages = new Hashtable (); 69 70 mboxFile = new File (folder.getDirectoryFile(), folder 71 .getId()); 72 73 messageFile = new File (folder.getDirectoryFile(), ".messages"); 74 75 if (!mboxFile.exists()) { 76 try { 77 mboxFile.createNewFile(); 78 } catch (IOException e) { 79 LOG.severe(e.getLocalizedMessage()); 80 } 81 } else { 82 try { 83 load(); 84 } catch (IOException e) { 85 LOG.severe(e.getLocalizedMessage()); 86 87 throw new RuntimeException ("Mailbox is corrupted!"); 88 } 89 } 90 91 } 92 93 96 public void removeMessage(Object uid) throws Exception { 97 MboxMessage message = (MboxMessage) messages.remove(uid); 98 99 if (uid.equals(largestUid)) { 100 FileChannel channel = new RandomAccessFile (mboxFile, "rw") 101 .getChannel(); 102 channel 103 .truncate(mboxFile.length() 104 - (message.getLength() + FROMLINE.length() + TERMLINE.length)); 105 channel.close(); 106 } else { 107 108 int intUid = ((Integer ) uid).intValue(); 109 110 deleteFilePart(mboxFile, message.getStart() - FROMLINE.length(), 111 message.getLength() + FROMLINE.length() + TERMLINE.length); 112 113 Enumeration uids = messages.keys(); 115 while (uids.hasMoreElements()) { 116 Integer actUid = (Integer ) uids.nextElement(); 117 118 if (actUid.intValue() > intUid) { 119 MboxMessage m = (MboxMessage) messages.get(actUid); 120 m 121 .setStart(m.getStart() 122 - (message.getLength() + FROMLINE.length() + TERMLINE.length)); 123 } 124 } 125 } 126 } 127 128 131 public Source getMessageSource(Object uid) throws Exception { 132 133 if( ! exists(uid)) throw new FolderInconsistentException(); 134 MboxMessage message = (MboxMessage) messages.get(uid); 135 136 137 FileInputStream in = new FileInputStream (mboxFile); 138 in.skip(message.getStart()); 139 140 File tempFile = File.createTempFile("mbox_message", ".tmp"); 141 tempFile.deleteOnExit(); 142 143 FileOutputStream out = new FileOutputStream (tempFile); 144 145 StreamUtils.streamCopy(in, out, (int) message.getLength()); 146 147 in.close(); 148 out.close(); 149 150 return new FileSource(tempFile); 151 } 152 153 156 public InputStream getMessageStream(Object uid) throws Exception { 157 MboxMessage message = (MboxMessage) messages.get(uid); 158 159 FileInputStream in = new FileInputStream (mboxFile); 160 in.skip(message.getStart()); 161 162 File tempFile = File.createTempFile("mbox_message", ".tmp"); 163 tempFile.deleteOnExit(); 164 165 FileOutputStream out = new FileOutputStream (tempFile); 166 167 StreamUtils.streamCopy(in, out, (int) message.getLength()); 168 169 in.close(); 170 out.close(); 171 172 return new FileInputStream (tempFile); 173 } 174 175 179 public void saveMessage(Object uid, InputStream source) throws Exception { 180 FileOutputStream out = new FileOutputStream (mboxFile, true); 181 out.write(FROMLINE.getBytes("US-ASCII")); 182 183 long pos = mboxFile.length(); 184 long length = StreamUtils.streamCopy(source, out); 185 186 out.write(TERMLINE); 187 out.close(); 188 189 messages.put(uid, new MboxMessage(uid, pos, length)); 190 191 largestUid = uid; 192 } 193 194 197 public int getMessageCount() { 198 return messages.size(); 199 } 200 201 204 public boolean exists(Object uid) throws Exception { 205 return messages.containsKey(uid); 206 } 207 208 211 public Object [] getMessageUids() { 212 return messages.keySet().toArray(); 213 } 214 215 223 protected void deleteFilePart(File file, long startpos, long length) 224 throws IOException { 225 RandomAccessFile ramFile = new RandomAccessFile (file, "rw"); 226 long oldlength = file.length(); 227 228 FileChannel channel1 = ramFile.getChannel(); 229 FileChannel channel2 = new FileInputStream (file).getChannel(); 230 231 channel2.position(startpos + length); 232 channel1.transferFrom(channel2, startpos, oldlength 233 - (length + startpos)); 234 channel2.close(); 235 236 channel1.truncate(oldlength - length); 237 channel1.close(); 238 } 239 240 protected void load() throws IOException { 241 ObjectInputStream in = new ObjectInputStream (new FileInputStream ( 242 messageFile)); 243 MboxMessage message; 244 245 int size = in.readInt(); 246 247 messages = new Hashtable (size); 248 for (int i = 0; i < size; i++) { 249 message = new MboxMessage(new Integer (in.readInt()), in.readLong(), 250 in.readLong()); 251 messages.put(message.getUid(), message); 252 } 253 254 in.close(); 255 } 256 257 public void save() throws IOException { 258 ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream ( 259 messageFile, false)); 260 MboxMessage message; 261 262 int size = messages.size(); 263 out.writeInt(size); 264 265 Enumeration message_enum = messages.elements(); 266 267 for (int i = 0; i < size; i++) { 268 message = (MboxMessage) message_enum.nextElement(); 269 270 out.writeInt(((Integer ) message.getUid()).intValue()); 271 out.writeLong(message.getStart()); 272 out.writeLong(message.getLength()); 273 } 274 275 out.close(); 276 } 277 278 279 } | Popular Tags |