001: /*
002: * ImapMessageCache.java
003: *
004: * Copyright (C) 2002 Peter Graves
005: * $Id: ImapMessageCache.java,v 1.1.1.1 2002/09/24 16:09:53 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j.mail;
023:
024: import java.io.BufferedReader;
025: import java.io.BufferedWriter;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.InputStreamReader;
029: import java.io.OutputStream;
030: import java.io.OutputStreamWriter;
031: import java.io.UnsupportedEncodingException;
032: import java.net.MalformedURLException;
033: import java.util.Enumeration;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Properties;
037: import org.armedbear.j.Directories;
038: import org.armedbear.j.File;
039: import org.armedbear.j.FastStringBuffer;
040: import org.armedbear.j.Headers;
041: import org.armedbear.j.Log;
042: import org.armedbear.j.Utilities;
043:
044: public final class ImapMessageCache {
045: private static Properties catalog;
046:
047: private final File cacheDirectory;
048: private final int uidValidity;
049:
050: private ImapMessageCache(File cacheDirectory, int uidValidity) {
051: this .cacheDirectory = cacheDirectory;
052: this .uidValidity = uidValidity;
053: }
054:
055: public int getUidValidity() {
056: return uidValidity;
057: }
058:
059: public static ImapMessageCache getMessageCache(ImapMailbox mb) {
060: File cacheDirectory = getCacheDirectory(mb);
061: if (cacheDirectory == null)
062: return null;
063: // Directory exists.
064: final int uidValidity = mb.getSession().getUidValidity();
065: File file = File.getInstance(cacheDirectory, "uidvalidity");
066: boolean ok = false;
067: if (file.isFile()) {
068: try {
069: BufferedReader reader = new BufferedReader(
070: new InputStreamReader(file.getInputStream()));
071: String s = reader.readLine();
072: reader.close();
073: int n = Integer.parseInt(s);
074: if (n == uidValidity)
075: ok = true;
076: else
077: Log.warn("getMessageCache UIDVALIDITY has changed");
078: } catch (Exception e) {
079: Log.error(e);
080: }
081: }
082: if (!ok) {
083: Log.debug("getMessageCache deleting old files");
084: String[] files = cacheDirectory.list();
085: for (int i = files.length - 1; i >= 0; i--)
086: File.getInstance(cacheDirectory, files[i]).delete();
087: Log.debug("getMessageCache writing UIDVALIDITY "
088: + uidValidity);
089: try {
090: BufferedWriter writer = new BufferedWriter(
091: new OutputStreamWriter(file.getOutputStream()));
092: writer.write(String.valueOf(uidValidity));
093: writer.flush();
094: writer.close();
095: } catch (IOException e) {
096: Log.error(e);
097: }
098: }
099: return new ImapMessageCache(cacheDirectory, uidValidity);
100: }
101:
102: public void store(int uid, String message, String encoding) {
103: Log.debug("store encoding = |" + encoding + "|");
104: if (encoding == null)
105: encoding = "ISO-8859-1";
106: if (!cacheDirectory.isDirectory()) {
107: cacheDirectory.mkdirs();
108: if (!cacheDirectory.isDirectory()) {
109: Log
110: .error("ImapMessageCache.store can't create cache directory");
111: return;
112: }
113: }
114: File file = File.getInstance(cacheDirectory, String
115: .valueOf(uid));
116: if (file == null)
117: return;
118: if (file.isFile()) {
119: Log
120: .debug("ImapMessageCache.store message is already cached");
121: return;
122: }
123: try {
124: BufferedWriter writer = null;
125: writer = new BufferedWriter(new OutputStreamWriter(file
126: .getOutputStream(), encoding));
127: writer.write(message);
128: writer.flush();
129: writer.close();
130: } catch (UnsupportedEncodingException e) {
131: Log.error(e);
132: } catch (IOException e) {
133: Log.error(e);
134: }
135: }
136:
137: public String getMessageText(int uid) {
138: File file = File.getInstance(cacheDirectory, String
139: .valueOf(uid));
140: if (file == null)
141: return null;
142: if (!file.isFile())
143: return null;
144: FastStringBuffer sb = new FastStringBuffer();
145: try {
146: BufferedReader reader = new BufferedReader(
147: new InputStreamReader(file.getInputStream()));
148: String s;
149: while ((s = reader.readLine()) != null) {
150: if (s.length() == 0)
151: break;
152: sb.append(s);
153: sb.append("\r\n");
154: }
155: reader.close();
156: } catch (Exception e) {
157: Log.error(e);
158: }
159: Headers headers = Headers.parse(sb.toString());
160: String charset = null;
161: String contentType = headers.getValue(Headers.CONTENT_TYPE);
162: if (contentType != null)
163: charset = Utilities.getCharsetFromContentType(contentType);
164: String encoding = Utilities.getEncodingFromCharset(charset);
165: sb.setLength(0);
166: try {
167: BufferedReader reader = new BufferedReader(
168: new InputStreamReader(file.getInputStream(),
169: encoding));
170: String s;
171: while ((s = reader.readLine()) != null) {
172: sb.append(s);
173: sb.append("\r\n");
174: }
175: reader.close();
176: } catch (Exception e) {
177: Log.error(e);
178: }
179: if (sb.length() > 0)
180: return sb.toString();
181: return null;
182: }
183:
184: public void removeDeletedEntries(List mailboxEntries) {
185: Log.debug("ImapMessageCache.removeDeletedEntries");
186: long start = System.currentTimeMillis();
187: Iterator it = mailboxEntries.iterator();
188: while (it.hasNext()) {
189: ImapMailboxEntry entry = (ImapMailboxEntry) it.next();
190: if (entry.isDeleted()) {
191: File file = File.getInstance(cacheDirectory, String
192: .valueOf(entry.getUid()));
193: if (file != null && file.isFile()) {
194: Log.debug("deleting " + file.netPath());
195: file.delete();
196: }
197: }
198: }
199: long elapsed = System.currentTimeMillis() - start;
200: Log.debug("ImapMessageCache.removeDeletedEntries " + elapsed
201: + " ms");
202: }
203:
204: private static synchronized File getCacheDirectory(ImapMailbox mb) {
205: final File parentDirectory = File.getInstance(Directories
206: .getMailDirectory(), "imap/cache");
207: if (!parentDirectory.isDirectory()) {
208: parentDirectory.mkdirs();
209: if (!parentDirectory.isDirectory()) {
210: Log.error("can't create IMAP cache directory");
211: return null;
212: }
213: }
214: File catalogFile = File.getInstance(parentDirectory, "catalog");
215: boolean modified = false;
216: if (catalog == null) {
217: // Load the catalog.
218: catalog = new Properties();
219: try {
220: if (catalogFile.isFile()) {
221: InputStream in = catalogFile.getInputStream();
222: catalog.load(in);
223: in.close();
224: }
225: } catch (IOException e) {
226: Log.error(e);
227: }
228: // Update obsolete catalog entries.
229: Properties temp = new Properties();
230: Enumeration keys = catalog.keys();
231: while (keys.hasMoreElements()) {
232: String key = (String) keys.nextElement();
233: String value = (String) catalog.get(key);
234: if (key.indexOf('@') < 0 || key.indexOf(':') < 0) {
235: // Obsolete format (i.e. not canonical mailbox name).
236: try {
237: ImapURL url = new ImapURL(key);
238: temp.put(url.getCanonicalName(), value);
239: } catch (MalformedURLException e) {
240: Log.error(e);
241: Log
242: .debug("deleting cached messages for "
243: + key);
244: File dir = File.getInstance(parentDirectory,
245: value);
246: if (dir != null && dir.isDirectory()) {
247: File[] files = dir.listFiles();
248: if (files != null) {
249: for (int i = files.length - 1; i >= 0; i--) {
250: Log.debug("deleting " + files[i]);
251: files[i].delete();
252: }
253: }
254: Log.debug("removing directory " + dir);
255: dir.delete();
256: }
257: }
258: modified = true;
259: } else
260: temp.put(key, value);
261: }
262: if (modified)
263: catalog = temp;
264: }
265: File cacheDirectory = null;
266: final String mailboxName = mb.getUrl().getCanonicalName();
267: final String directoryName = catalog.getProperty(mailboxName);
268: if (directoryName == null) {
269: // Not found.
270: cacheDirectory = Utilities.getTempFile(parentDirectory);
271: if (cacheDirectory != null) {
272: boolean directoryExists = cacheDirectory.isDirectory();
273: if (!directoryExists) {
274: cacheDirectory.mkdirs();
275: directoryExists = cacheDirectory.isDirectory();
276: }
277: if (directoryExists) {
278: // Cache directory exists.
279: catalog.put(mailboxName, cacheDirectory.getName());
280: modified = true;
281: } else
282: cacheDirectory = null;
283: }
284: if (cacheDirectory == null)
285: Log.error("can't create IMAP cache directory");
286: } else
287: cacheDirectory = File.getInstance(parentDirectory,
288: directoryName);
289: if (modified) {
290: Log.debug("saving modified catalog");
291: try {
292: OutputStream out = catalogFile.getOutputStream();
293: catalog.save(out, null);
294: out.flush();
295: out.close();
296: } catch (IOException e) {
297: Log.error(e);
298: }
299: }
300: return cacheDirectory;
301: }
302: }
|