KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > mail > pop3 > POP3Server


1 // The contents of this file are subject to the Mozilla Public License Version
2
// 1.1
3
//(the "License"); you may not use this file except in compliance with the
4
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
5
//
6
//Software distributed under the License is distributed on an "AS IS" basis,
7
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8
//for the specific language governing rights and
9
//limitations under the License.
10
//
11
//The Original Code is "The Columba Project"
12
//
13
//The Initial Developers of the Original Code are Frederik Dietz and Timo
14
// Stich.
15
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
16
//
17
//All Rights Reserved.
18
package org.columba.mail.pop3;
19
20 import java.io.File JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.util.Date JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.logging.Logger JavaDoc;
28
29 import org.columba.api.command.IStatusObservable;
30 import org.columba.api.command.IWorkerStatusController;
31 import org.columba.core.base.ListTools;
32 import org.columba.core.base.Lock;
33 import org.columba.core.command.CommandCancelledException;
34 import org.columba.core.command.ProgressObservedInputStream;
35 import org.columba.mail.config.AccountItem;
36 import org.columba.mail.config.MailConfig;
37 import org.columba.mail.config.PopItem;
38 import org.columba.mail.config.SpecialFoldersItem;
39 import org.columba.mail.folder.IMailbox;
40 import org.columba.mail.folder.headercache.BerkeleyDBHeaderList;
41 import org.columba.mail.gui.tree.FolderTreeModel;
42 import org.columba.mail.message.ColumbaHeader;
43 import org.columba.mail.message.ColumbaMessage;
44 import org.columba.mail.message.ICloseableIterator;
45 import org.columba.mail.message.IColumbaHeader;
46 import org.columba.mail.message.IHeaderList;
47 import org.columba.mail.message.IPersistantHeaderList;
48 import org.columba.ristretto.io.Source;
49 import org.columba.ristretto.io.TempSourceFactory;
50 import org.columba.ristretto.message.Header;
51 import org.columba.ristretto.parser.HeaderParser;
52 import org.columba.ristretto.parser.ParserException;
53 import org.columba.ristretto.pop3.MessageNotOnServerException;
54 import org.columba.ristretto.pop3.POP3Exception;
55
56 /**
57  * Highest Abstraction Layer of the POP3 Protocol. Its responsabilities are the
58  * synchornization of already downloaded mails, deletion of mails after x days
59  * and parsing of the headers to maintain a headerCache of the downloaded mails.
60  *
61  * @author tstich
62  */

63 public class POP3Server {
64     /** JDK 1.4+ logging framework logger, used for logging. */
65     private static final Logger JavaDoc LOG = Logger
66             .getLogger("org.columba.mail.folder.headercache");
67
68     private static final long DAY_IN_MS = 24 * 60 * 60 * 1000;
69
70     private AccountItem accountItem;
71
72     private File JavaDoc file;
73
74     private POP3Store store;
75
76     protected IPersistantHeaderList headerList;
77
78     private Lock lock;
79
80     /**
81      * Dirty flag. If set to true, we have to save the headercache changes. If
82      * set to false, nothing changed. Therefore no need to save the headercache.
83      */

84     private boolean cacheChanged;
85
86     public POP3Server(AccountItem accountItem) {
87         this.accountItem = accountItem;
88
89         int uid = accountItem.getUid();
90
91         file = new File JavaDoc(MailConfig.getInstance().getPOP3Directory(),
92                 (new Integer JavaDoc(uid)).toString());
93
94         PopItem item = accountItem.getPopItem();
95
96         store = new POP3Store(item);
97
98         if(!this.getConfigFile().isDirectory()) this.getConfigFile().delete();
99         File JavaDoc headercacheDirectory = new File JavaDoc(file, "pop3"+uid);
100         headerList = new BerkeleyDBHeaderList(headercacheDirectory, "pop3_" + uid, new POP3HeaderBinding());
101         ((BerkeleyDBHeaderList)headerList).setKeyType(String JavaDoc.class);
102         
103         lock = new Lock();
104
105         setCacheChanged(false);
106     }
107
108     public void save() throws Exception JavaDoc {
109         headerList.persist();
110     }
111
112     public File JavaDoc getConfigFile() {
113         return file;
114     }
115
116     public AccountItem getAccountItem() {
117         return accountItem;
118     }
119
120     public IMailbox getFolder() {
121         SpecialFoldersItem foldersItem = accountItem.getSpecialFoldersItem();
122         String JavaDoc inboxStr = foldersItem.get("inbox");
123
124             IMailbox f = (IMailbox) FolderTreeModel.getInstance().getFolder(
125                 inboxStr);
126
127         return f;
128     }
129
130     public void logout() throws Exception JavaDoc {
131         getStore().logout();
132     }
133
134     public List JavaDoc synchronize() throws Exception JavaDoc {
135         if (getHeaderList().count() == 0) {
136             LOG.severe(accountItem.getName() + " - POP3 Headerlist is empty!");
137         }
138
139         // Get the uids from the headercache
140

141         LinkedList JavaDoc headerUids = new LinkedList JavaDoc(getHeaderList().keySet());
142         
143         // Get the list of the uids on the server
144
// Important: Use a clone of the List since
145
// we must not change it!
146
List JavaDoc newUids = store.getUIDList();
147
148         // substract the uids that we already downloaded ->
149
// newUids contains all uids to fetch from the server
150
ListTools.substract(newUids, headerUids);
151
152         // substract the uids on the server from the downloaded uids ->
153
// headerUids are the uids that have been removed from the server
154
ListTools.substract(headerUids, store.getUIDList());
155
156         Iterator JavaDoc it = headerUids.iterator();
157
158         // update the cache
159
while (it.hasNext()) {
160             getHeaderList().remove(it.next());
161             cacheChanged = true;
162         }
163
164         // return the uids that are new
165
return newUids;
166     }
167
168     public void deleteMessage(Object JavaDoc uid) throws IOException JavaDoc, POP3Exception,
169             CommandCancelledException {
170         try {
171             store.deleteMessage(uid);
172
173             getHeaderList().remove(uid);
174
175             // set dirty flag
176
setCacheChanged(true);
177         } catch (POP3Exception e) {
178             if ((e instanceof MessageNotOnServerException)
179                     || (e.getResponse() != null && e.getResponse().isERR())) {
180                 // Message already deleted from server
181
getHeaderList().remove(uid);
182                 setCacheChanged(true);
183             } else
184                 throw e;
185         }
186
187     }
188
189     public void deleteMessagesOlderThan(Date JavaDoc date) throws IOException JavaDoc,
190             POP3Exception, CommandCancelledException {
191         LOG.info("Removing message older than " + date);
192         IHeaderList headerList = getHeaderList();
193         ICloseableIterator it = headerList.headerIterator();
194         while (it.hasNext()) {
195             IColumbaHeader header = (IColumbaHeader) it.next();
196             if (((Date JavaDoc) header.get("columba.date")).before(date)) {
197                 deleteMessage(header.get("columba.uid"));
198             }
199         }
200         it.close();
201     }
202
203     public void cleanUpServer() throws IOException JavaDoc, POP3Exception,
204             CommandCancelledException {
205         PopItem item = getAccountItem().getPopItem();
206
207         if (item.getBooleanWithDefault("leave_messages_on_server", false)
208                 && item.getBooleanWithDefault("remove_old_from_server", false)) {
209             int days = item.getInteger("older_than");
210             long date = new Date JavaDoc().getTime();
211             date -= days * DAY_IN_MS;
212
213             deleteMessagesOlderThan(new Date JavaDoc(date));
214         } else if (!item.getBooleanWithDefault("leave_messages_on_server",
215                 false)) {
216             removeAllDownloadedMessages();
217         }
218     }
219
220     private void removeAllDownloadedMessages() throws IOException JavaDoc,
221             CommandCancelledException, POP3Exception {
222         IHeaderList headerList = getHeaderList();
223         ICloseableIterator it = headerList.keyIterator();
224         while (it.hasNext()) {
225             deleteMessage(it.next());
226         }
227         it.close();
228     }
229
230     private IHeaderList getHeaderList() {
231         return headerList;
232     }
233
234     public int getMessageCount() throws Exception JavaDoc {
235         return getStore().getMessageCount();
236     }
237
238     public ColumbaMessage getMessage(Object JavaDoc uid, IWorkerStatusController worker)
239             throws IOException JavaDoc, POP3Exception, CommandCancelledException,
240             ParserException {
241         InputStream JavaDoc messageStream = new ProgressObservedInputStream(getStore()
242                 .fetchMessage(store.getIndex(uid)), worker, true);
243
244         // Store the complete stream in a source so that we can parse it
245
Source source = TempSourceFactory.createTempSource(messageStream, -1);
246
247         // pipe through preprocessing filter
248
// if (popItem.getBoolean("enable_pop3preprocessingfilter", false))
249
// rawString = modifyMessage(rawString);
250
// UPDATE! @author fdietz
251
// was:
252
// Activate PreProcessor again with Source instead of String
253
// new goal:
254
// completely remove preprocessor -> we never change the message source!
255
ColumbaMessage m;
256         try {
257             Header header = HeaderParser.parse(source);
258
259             m = new ColumbaMessage(header);
260             ColumbaHeader h = (ColumbaHeader) m.getHeader();
261
262             m.setSource(source);
263             h.getAttributes().put("columba.pop3uid", uid);
264             // message size should be at least 1 KB
265
int size = Math.max(source.length() / 1024, 1);
266             h.getAttributes().put("columba.size", new Integer JavaDoc(size));
267
268             // set the attachment flag
269
h.getAttributes().put("columba.attachment", h.hasAttachments());
270             h.getAttributes().put("columba.fetchstate", Boolean.TRUE);
271             h.getAttributes().put("columba.accountuid",
272                     new Integer JavaDoc(accountItem.getInteger("uid")));
273
274             getHeaderList().add(h, uid);
275         } catch (ParserException e) {
276             LOG
277                     .severe("Skipped message: Error parsing message. Message source:\n "
278                             + source);
279             return null;
280         }
281
282         // set headercache dirty flag
283
setCacheChanged(true);
284
285         return m;
286     }
287
288     public int getMessageSize(Object JavaDoc uid) throws Exception JavaDoc {
289         return store.getSize(store.getIndex(uid));
290     }
291
292     public String JavaDoc getFolderName() {
293         return accountItem.getName();
294     }
295
296     /**
297      * Returns the store.
298      *
299      * @return POP3Store
300      */

301     public POP3Store getStore() {
302         return store;
303     }
304
305     public IStatusObservable getObservable() {
306         return store.getObservable();
307     }
308
309     public boolean tryToGetLock(Object JavaDoc locker) {
310         return lock.tryToGetLock(locker);
311     }
312
313     public void releaseLock(Object JavaDoc locker) {
314         lock.release(locker);
315     }
316
317     /**
318      * @return Returns the hasChanged.
319      */

320     public boolean isCacheChanged() {
321         return cacheChanged;
322     }
323
324     /**
325      * @param hasChanged
326      * The hasChanged to set.
327      */

328     private void setCacheChanged(boolean hasChanged) {
329         this.cacheChanged = hasChanged;
330     }
331
332     /**
333      * Call this method if the underlying configuration changed.
334      */

335     public void updateConfig() {
336         PopItem item = accountItem.getPopItem();
337
338         store = new POP3Store(item);
339     }
340
341     /**
342      * @throws IOException
343      *
344      */

345     public void dropConnection() throws IOException JavaDoc {
346         store.dropConnection();
347     }
348 }
Popular Tags