KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > suberic > pooka > PopInboxFolderInfo


1 package net.suberic.pooka;
2 import javax.mail.*;
3 import javax.mail.internet.*;
4 import javax.mail.event.MessageCountEvent JavaDoc;
5 import javax.mail.event.MessageChangedEvent JavaDoc;
6 import java.io.*;
7 import java.util.Vector JavaDoc;
8 import java.util.HashSet JavaDoc;
9 import java.util.Set JavaDoc;
10 import java.util.List JavaDoc;
11 import net.suberic.pooka.cache.ChangeCache;
12 import net.suberic.pooka.gui.MessageProxy;
13
14 /**
15  * This represents the Inbox of a Pop3 folder. It has an mbox backend, but
16  * uses the pop folder to get new messages.
17  */

18 public class PopInboxFolderInfo extends FolderInfo {
19
20   Store popStore;
21   Folder popInbox;
22   ChangeCache changeAdapter;
23   String JavaDoc mailHome;
24
25   Set JavaDoc uidsRead = new HashSet JavaDoc();
26
27   public static String JavaDoc UID_HEADER = "X-Pooka-Pop-UID";
28
29   /**
30    * Creates a new FolderInfo from a parent StoreInfo and a Folder
31    * name.
32    */

33
34   public PopInboxFolderInfo(StoreInfo parent, String JavaDoc fname) {
35     super(parent, fname);
36
37     // create the pop folder.
38
configurePopStore(parent.getStoreID());
39   }
40
41   private void configurePopStore(String JavaDoc storeID) {
42     String JavaDoc user = Pooka.getProperty("Store." + storeID + ".user", "");
43     String JavaDoc password = Pooka.getProperty("Store." + storeID + ".password", "");
44     if (!password.equals(""))
45       password = net.suberic.util.gui.propedit.PasswordEditorPane.descrambleString(password);
46     String JavaDoc server = Pooka.getProperty("Store." + storeID + ".server", "");
47     String JavaDoc protocol = Pooka.getProperty("Store." + storeID + ".protocol", "");
48     if (Pooka.getProperty(getParentStore().getStoreProperty() + ".SSL", "false").equalsIgnoreCase("true")) {
49       protocol = "pop3s";
50     }
51
52     URLName url = new URLName(protocol, server, -1, "", user, password);
53
54     mailHome = Pooka.getProperty("Store." + storeID + ".mailDir", "");
55     if (mailHome.equals("")) {
56       mailHome = Pooka.getProperty("Pooka.defaultMailSubDir", "");
57       if (mailHome.equals(""))
58         mailHome = System.getProperty("user.home") + File.separator + ".pooka";
59
60       mailHome = mailHome + File.separator + storeID;
61     }
62     String JavaDoc inboxFileName = mailHome + File.separator + Pooka.getProperty("Pooka.inboxName", "INBOX");
63     String JavaDoc userHomeName = mailHome + File.separator + Pooka.getProperty("Pooka.subFolderName", "folders");
64
65     try {
66       File userHomeDir = new File(userHomeName);
67       if (! userHomeDir.exists())
68         userHomeDir.mkdirs();
69
70       File inboxFile = new File(inboxFileName);
71       if (! inboxFile.exists())
72         inboxFile.createNewFile();
73     } catch (Exception JavaDoc e) {
74       Pooka.getUIFactory().showError(Pooka.getProperty("error.cannotCreatePopFolders", "Error: could not create local folder."), e);
75     }
76
77     changeAdapter = new ChangeCache(new File(mailHome));
78
79     try {
80       java.util.Properties JavaDoc props = new java.util.Properties JavaDoc(System.getProperties());
81
82       if (Pooka.getProperty(getParentStore().getStoreProperty() + ".SSL", "false").equalsIgnoreCase("true")) {
83         //props.setProperty("mail.pop3s.socketFactory.class", "net.suberic.pooka.ssl.PookaSSLSocketFactory");
84
props.setProperty("mail.pop3s.socketFactory.fallback", Pooka.getProperty(getParentStore().getStoreProperty() + ".SSL.fallback", "false"));
85         //props.setProperty("mail.pop3s.socketFactory.port", Pooka.getProperty(getParentStore().getStoreProperty() + ".SSL.port", "995"));
86
}
87
88       Session session = javax.mail.Session.getInstance(props, Pooka.getDefaultAuthenticator());
89
90       if (Pooka.isDebug()) {
91         System.out.println("session.getProperty(mail.mbox.inbox) = " + session.getProperty("mail.mbox.inbox"));
92         System.out.println("url is " + url);
93       }
94       popStore = session.getStore(url);
95     } catch (NoSuchProviderException nspe) {
96       nspe.printStackTrace();
97       // available=false;
98
}
99   }
100
101
102   /**
103    * This method opens the Folder, and sets the FolderInfo to know that
104    * the Folder should be open. You should use this method instead of
105    * calling getFolder().open(), because if you use this method, then
106    * the FolderInfo will try to keep the Folder open, and will try to
107    * reopen the Folder if it gets closed before closeFolder is called.
108    *
109    * This method can also be used to reset the mode of an already
110    * opened folder.
111    */

112   public void openFolder(int mode, boolean pConnectStore) throws MessagingException {
113     // identical to FolderInfo.openFolder() except that we don't check
114
// to make sure that the mode matches.
115

116     if (Pooka.isDebug())
117       System.out.println(this + ": checking parent store.");
118
119     if (!getParentStore().isConnected() && pConnectStore) {
120       if (Pooka.isDebug())
121         System.out.println(this + ": parent store isn't connected. trying connection.");
122       getParentStore().connectStore();
123     }
124
125     if (Pooka.isDebug())
126       System.out.println(this + ": loading folder.");
127
128     if (! isLoaded() && status != CACHE_ONLY)
129       loadFolder();
130
131     if (Pooka.isDebug())
132       System.out.println(this + ": folder loaded. status is " + status);
133
134     if (Pooka.isDebug())
135       System.out.println(this + ": checked on parent store. trying isLoaded() and isAvailable().");
136
137     if (status == CLOSED || status == LOST_CONNECTION || status == DISCONNECTED) {
138       if (Pooka.isDebug())
139         System.out.println(this + ": isLoaded() and isAvailable().");
140       if (getFolder().isOpen()) {
141         return;
142       } else {
143         getFolder().open(mode);
144         updateFolderOpenStatus(true);
145         resetMessageCounts();
146       }
147     } else if (status == INVALID) {
148       throw new MessagingException(Pooka.getProperty("error.folderInvalid", "Error: folder is invalid. ") + getFolderID());
149     }
150   }
151
152   /**
153    * <p> Loads all Messages into a new FolderTableModel, sets this
154    * FolderTableModel as the current FolderTableModel, and then returns
155    * said FolderTableModel. This is the basic way to populate a new
156    * FolderTableModel.</p>
157    */

158   public synchronized void loadAllMessages() throws MessagingException {
159     if (folderTableModel == null) {
160       super.loadAllMessages();
161       // let's see how bad performance is for the mbox provider. :)
162
populateUidMap();
163       checkFolder();
164     }
165   }
166
167   /**
168    * <p>Populates the UID map from the list of MessageProxies.</p>
169    */

170   void populateUidMap() {
171     if (folderTableModel != null) {
172       List JavaDoc v = folderTableModel.getAllProxies();
173       for (int i = 0; i < v.size(); i++) {
174         MessageProxy mp = (MessageProxy) v.get(i);
175         try {
176           String JavaDoc uid = (String JavaDoc) mp.getMessageInfo().getMessageProperty(UID_HEADER);
177           uidsRead.add(uid);
178           if (Pooka.isDebug())
179             System.out.println("adding " + uid + " to read list.");
180         } catch (MessagingException me) {
181           Pooka.getUIFactory().showError("Error getting UID for message: ", me);
182         }
183       }
184     }
185   }
186
187   /**
188    * Checks the pop folder for new messages. If deleteOnServerOnLocalDelete
189    * is set to true, this will also go through and remove any messages
190    * on the server that have been removed on the local client.
191    */

192   public void checkFolder() throws MessagingException {
193     if (Pooka.isDebug())
194       System.out.println("checking folder " + getFolderName());
195
196     Folder f = null;
197
198     if (isConnected() && popStore != null) {
199       if (Pooka.isDebug())
200         System.out.println("checking folder " + getFolderName() + ": opening pop store.");
201
202       NetworkConnection connection = getParentStore().getConnection();
203       int originalStatus = -1;
204
205       if (connection != null) {
206         originalStatus = connection.getStatus();
207         if (connection.getStatus() == NetworkConnection.DISCONNECTED) {
208           connection.connect();
209         }
210
211         if (connection.getStatus() != NetworkConnection.CONNECTED) {
212           throw new MessagingException(Pooka.getProperty("error.connectionDown", "Connection down for checking folder: ") + getFolderID());
213         }
214       }
215
216       try {
217         popStore.connect();
218         f = popStore.getDefaultFolder().getFolder("INBOX");
219         if (f != null) {
220           f.open(Folder.READ_WRITE);
221           Message[] msgs = getNewMessages(f);
222
223           if (msgs != null && msgs.length > 0) {
224             MimeMessage[] msgsToAppend = new MimeMessage[msgs.length];
225             Pooka.getUIFactory().showStatusMessage(getFolderID() + ": loading " + msgs.length + " messages...");
226             for (int i = 0; i < msgs.length; i++) {
227               msgsToAppend[i] = new MimeMessage((MimeMessage) msgs[i]);
228               String JavaDoc uid = getUID(msgs[i], f);
229               msgsToAppend[i].addHeader(UID_HEADER, uid);
230               msgsToAppend[i].setFlag(Flags.Flag.RECENT, true);
231               uidsRead.add(uid);
232               if (Pooka.isDebug())
233                 System.out.println("adding " + uid + " to read list.");
234               Pooka.getUIFactory().showStatusMessage(getFolderID() + ": loading " + i + " of " + msgs.length + " messages...");
235
236             }
237             if (Pooka.isDebug())
238               System.out.println(Thread.currentThread() + ": running appendMessages; # of added messages is " + msgsToAppend.length);
239
240             Pooka.getUIFactory().showStatusMessage(getFolderID() + ": appending " + msgs.length + " messages to local folder...");
241
242             getFolder().appendMessages(msgsToAppend);
243
244             Pooka.getUIFactory().clearStatus();
245
246             if (! leaveMessagesOnServer()) {
247               if (Pooka.isDebug())
248                 System.out.println("removing all messages.");
249
250               for (int i = 0; i < msgs.length; i++) {
251                 msgs[i].setFlag(Flags.Flag.DELETED, true);
252                 if (Pooka.isDebug())
253                   System.out.println("marked message " + i + " to be deleted. isDelted = " + msgs[i].isSet(Flags.Flag.DELETED));
254               }
255             }
256           }
257
258           if (isDeletingOnServer()) {
259             removeDeletedMessages(f);
260           }
261
262           f.close(true);
263           popStore.close();
264         }
265         resetMessageCounts();
266       } catch ( MessagingException me ) {
267         try {
268           if (f != null && f.isOpen())
269             f.close(false);
270         } catch (Exception JavaDoc e ) {
271         }
272         throw me;
273       } finally {
274         try {
275           popStore.close();
276         } catch (Exception JavaDoc e) {
277         }
278
279         if (connection != null) {
280           if (originalStatus == NetworkConnection.DISCONNECTED && originalStatus != connection.getStatus())
281             connection.disconnect();
282         }
283       }
284     }
285
286   }
287
288   /**
289    * This does the real work when messages are removed.
290    *
291    * This method should always be run on the FolderThread.
292    */

293   protected void runMessagesRemoved(MessageCountEvent JavaDoc mce) {
294     if (folderTableModel != null) {
295       Message[] removedMessages = mce.getMessages();
296       if (Pooka.isDebug())
297         System.out.println("removedMessages was of size " + removedMessages.length);
298       MessageInfo mi;
299       Vector JavaDoc removedProxies=new Vector JavaDoc();
300       for (int i = 0; i < removedMessages.length; i++) {
301         if (Pooka.isDebug())
302           System.out.println("checking for existence of message.");
303
304         // first, if we're removed from the pop3 folder on deletion,
305
// we need to note that this message has been removed.
306

307         if (isDeletingOnServer()) {
308           try {
309             MimeMessage mm = (MimeMessage) removedMessages[i];
310             String JavaDoc uid = mm.getHeader(UID_HEADER, ":");
311             if (uid != null)
312               getChangeAdapter().setFlags(uid, new Flags(Flags.Flag.DELETED), true);
313           } catch (Exception JavaDoc e) {
314           }
315         }
316
317         mi = getMessageInfo(removedMessages[i]);
318         if (mi.getMessageProxy() != null)
319           mi.getMessageProxy().close();
320
321         if (mi != null) {
322           if (Pooka.isDebug())
323             System.out.println("message exists--removing");
324           removedProxies.add(mi.getMessageProxy());
325           messageToInfoTable.remove(mi);
326         }
327       }
328       if (getFolderDisplayUI() != null) {
329         if (removedProxies.size() > 0)
330           getFolderDisplayUI().removeRows(removedProxies);
331         resetMessageCounts();
332         fireMessageCountEvent(mce);
333       } else {
334         resetMessageCounts();
335         fireMessageCountEvent(mce);
336         if (removedProxies.size() > 0)
337           getFolderTableModel().removeRows(removedProxies);
338       }
339     } else {
340       resetMessageCounts();
341       fireMessageCountEvent(mce);
342     }
343   }
344
345   /**
346    * <p>Overrides FolderInfo.fireMessageChangedEvent().</p>
347    */

348   public void fireMessageChangedEvent(MessageChangedEvent JavaDoc mce) {
349     // if this is just from the TableInfo reloading, skip it.
350
if (! (mce instanceof net.suberic.pooka.event.MessageTableInfoChangedEvent)) {
351       try {
352         if (!mce.getMessage().isSet(Flags.Flag.DELETED) || ! Pooka.getProperty("Pooka.autoExpunge", "true").equalsIgnoreCase("true")) {
353
354           MessageInfo mi = getMessageInfo(mce.getMessage());
355           MessageProxy mp = mi.getMessageProxy();
356           if (mp != null) {
357             if (mce.getMessageChangeType() == MessageChangedEvent.FLAGS_CHANGED) {
358               mi.refreshFlags();
359             } else if (mce.getMessageChangeType() == MessageChangedEvent.ENVELOPE_CHANGED) {
360               mi.refreshHeaders();
361             }
362             mp.unloadTableInfo();
363             mp.loadTableInfo();
364           }
365         }
366       } catch (MessagingException me) {
367         // if we catch a MessagingException, it just means
368
// that the message has already been expunged.
369
}
370     }
371
372     super.fireMessageChangedEvent(mce);
373
374   }
375
376   /**
377    * This retrieves new messages from the pop folder.
378    */

379   public Message[] getNewMessages(Folder f) throws MessagingException {
380     if (Pooka.isDebug())
381       System.out.println("getting new messages.");
382     Message[] newMessages = f.getMessages();
383
384     if (newMessages.length > 0) {
385       // if none of the messages have been read, then lastRead will be -1.
386
int lastRead = newMessages.length - 1;
387       while (lastRead >=0 && ! alreadyRead(newMessages[lastRead], f)) {
388         lastRead--;
389       }
390
391       if (Pooka.isDebug())
392         System.out.println("final lastRead is " + lastRead + "; for reference, newMessages.length = " + newMessages.length);
393       if (newMessages.length - lastRead < 2) {
394         // no new messages
395
if (Pooka.isDebug())
396           System.out.println("no new messages.");
397         return new Message[0];
398       } else {
399         if (Pooka.isDebug())
400           System.out.println("returning " + (newMessages.length - lastRead - 1) + " new messages.");
401         Message[] returnValue = new Message[newMessages.length - lastRead - 1];
402         System.arraycopy(newMessages, lastRead + 1, returnValue, 0, newMessages.length - lastRead - 1);
403
404         return returnValue;
405       }
406     } else {
407       if (Pooka.isDebug())
408         System.out.println("no messages in folder.");
409       // no messages.
410
return newMessages;
411     }
412   }
413
414   public String JavaDoc readLastUid() throws IOException {
415     File uidFile = new File(mailHome + File.separator + ".pooka-lastUid");
416     if (uidFile.exists()) {
417       BufferedReader br = new BufferedReader(new FileReader(uidFile));
418       String JavaDoc lastUid = br.readLine();
419       if (Pooka.isDebug())
420         System.out.println("lastUid is " + lastUid);
421
422       br.close();
423
424       return lastUid;
425     }
426
427     return null;
428   }
429
430   public void writeLastUid(String JavaDoc lastUid) throws IOException {
431     File uidFile = new File(mailHome + File.separator + ".pooka-lastUid");
432     if (uidFile.exists()) {
433       uidFile.delete();
434     }
435
436     uidFile.createNewFile();
437
438     BufferedWriter bw = new BufferedWriter(new FileWriter(uidFile));
439
440     bw.write(lastUid);
441     bw.newLine();
442
443     bw.flush();
444     bw.close();
445
446   }
447
448   public String JavaDoc getUID(Message m, Folder f) throws MessagingException {
449     return ((com.sun.mail.pop3.POP3Folder)f).getUID(m);
450   }
451
452   public void removeDeletedMessages(Folder f) throws MessagingException {
453     try {
454       getChangeAdapter().writeChanges((com.sun.mail.pop3.POP3Folder)f);
455     } catch (java.io.IOException JavaDoc ioe) {
456       throw new MessagingException("Error", ioe);
457     }
458   }
459
460   public boolean isDeletingOnServer() {
461     return Pooka.getProperty(getParentStore().getStoreProperty() + ".deleteOnServerOnLocalDelete", "false").equalsIgnoreCase("true");
462
463   }
464
465   public boolean leaveMessagesOnServer() {
466     return Pooka.getProperty(getParentStore().getStoreProperty() + ".leaveMessagesOnServer", "false").equalsIgnoreCase("true");
467   }
468
469   public ChangeCache getChangeAdapter() {
470     return changeAdapter;
471   }
472
473   /**
474    * <p>Checks to see whether or not we've already read this message.
475    * Used when we're leaving messages on the server.
476    */

477   public boolean alreadyRead(Message m, Folder f) throws javax.mail.MessagingException JavaDoc {
478     String JavaDoc newUid = getUID(m, f);
479     if (Pooka.isDebug())
480       System.out.println("checking to see if message with uid " + newUid + " is new.");
481
482     boolean returnValue = uidsRead.contains(newUid);
483
484     if (Pooka.isDebug())
485       System.out.println(newUid + " already read = " + returnValue);
486
487     return returnValue;
488
489   }
490 }
491
492
Popular Tags