KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.suberic.pooka;
2
3 import javax.mail.*;
4 import javax.mail.event.*;
5 import javax.swing.event.EventListenerList JavaDoc;
6 import java.util.*;
7 import java.util.logging.Logger JavaDoc;
8 import java.util.logging.Level JavaDoc;
9
10 import net.suberic.pooka.gui.*;
11 import net.suberic.util.ValueChangeListener;
12 import net.suberic.util.thread.ActionThread;
13 import net.suberic.util.VariableBundle;
14 import net.suberic.util.Item;
15
16 /**
17  * This class does all of the work for a Store. It keeps track of the
18  * StoreNode for the Store, as well as keeping the children of the store
19  * and the properties of the Store.
20  */

21
22 public class StoreInfo implements ValueChangeListener, Item, NetworkConnectionListener {
23
24   // logger
25
Logger JavaDoc mLogger = null;
26
27   // the actual connection information
28
private Store store;
29   private Session mSession;
30
31   // The is the store ID.
32
private String JavaDoc storeID;
33
34   // Information for the StoreNode
35
private StoreNode storeNode;
36   private Vector children;
37
38   // the status indicators
39
private boolean connected = false;
40   private boolean authorized = false;
41   private boolean available = false;
42
43   // if this is a pop mailbox.
44
private boolean popStore = false;
45
46   private UserProfile defaultProfile;
47
48   private NetworkConnection connection;
49
50   // the connection information.
51
private String JavaDoc user;
52   private String JavaDoc password;
53   private String JavaDoc server;
54   private String JavaDoc protocol;
55   private int port;
56   private URLName url;
57
58   private String JavaDoc sslSetting = "none";
59
60   // the Thread for connections to this Store.
61
private ActionThread storeThread;
62
63   // the Trash folder for this Store, if any.
64
private FolderInfo trashFolder;
65
66   // whether or not this store synchronizes with the subscribed folders
67
// automatically
68
private boolean useSubscribed = false;
69
70   // the connection listener for this store.
71
private ConnectionListener connectionListener;
72
73   /**
74    * Creates a new StoreInfo from a Store ID.
75    */

76   public StoreInfo(String JavaDoc sid) {
77     setStoreID(sid);
78
79     configureStore();
80   }
81
82   /**
83    * This configures the store from the property information.
84    */

85   public void configureStore() {
86     connected = false;
87     authorized = false;
88     available = false;
89
90     protocol = Pooka.getProperty("Store." + storeID + ".protocol", "");
91
92     if (protocol.equalsIgnoreCase("pop3")) {
93       user = "";
94       password = "";
95       server = "localhost";
96       if (Pooka.getProperty(getStoreProperty() + ".useMaildir", "unset").equalsIgnoreCase("true"))
97         protocol = "maildir";
98       else
99         protocol = "mbox";
100       port = -1;
101       popStore = true;
102     } else {
103       popStore = false;
104       user = Pooka.getProperty("Store." + storeID + ".user", "");
105       password = Pooka.getProperty("Store." + storeID + ".password", "");
106       String JavaDoc portValue = Pooka.getProperty("Store." + storeID + ".port", "");
107       port = -1;
108       if (!portValue.equals("")) {
109         try {
110           port = Integer.parseInt(portValue);
111         } catch (Exception JavaDoc e) {
112         }
113       }
114       if (!password.equals(""))
115         password = net.suberic.util.gui.propedit.PasswordEditorPane.descrambleString(password);
116       server = Pooka.getProperty("Store." + storeID + ".server", "");
117
118       sslSetting = Pooka.getProperty(getStoreProperty() + ".SSL", "none");
119       if (sslSetting.equalsIgnoreCase("true")) {
120         Pooka.setProperty(getStoreProperty() + ".SSL", "ssl");
121         sslSetting = "ssl";
122       } else if (sslSetting.equalsIgnoreCase("false")) {
123         Pooka.setProperty(getStoreProperty() + ".SSL", "none");
124         sslSetting = "none";
125       }
126
127       if (sslSetting.equals("ssl")) {
128         if (protocol.equals("imap"))
129           protocol = "imaps";
130       }
131     }
132
133
134     Properties p = loadProperties();
135
136     if (protocol.equalsIgnoreCase("maildir")) {
137       url = new URLName(protocol, server, port, p.getProperty("mail.store.maildir.baseDir"), user, password);
138     } else {
139       url = new URLName(protocol, server, port, "", user, password);
140     }
141
142     try {
143       mSession = Session.getInstance(p, Pooka.getDefaultAuthenticator());
144
145       updateSessionDebug();
146
147       store = mSession.getStore(url);
148       available=true;
149     } catch (NoSuchProviderException nspe) {
150       Pooka.getUIFactory().showError(Pooka.getProperty("error.loadingStore", "Unable to load Store ") + getStoreID(), nspe);
151       available=false;
152     }
153
154     // don't allow a StoreInfo to get created with an empty folderList.
155

156     if (Pooka.getProperty("Store." + storeID + ".folderList", "").equals(""))
157       Pooka.setProperty("Store." + storeID + ".folderList", "INBOX");
158
159     // check to see if we're using the subscribed property.
160
useSubscribed = Pooka.getProperty(getStoreProperty() + ".useSubscribed", "false").equalsIgnoreCase("true");
161
162     Pooka.getResources().addValueChangeListener(this, getStoreProperty());
163     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".folderList");
164     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".defaultProfile");
165     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".protocol");
166     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".user");
167     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".password");
168     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".server");
169     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".port");
170     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".connection");
171     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".SSL");
172     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".useSubscribed");
173     Pooka.getResources().addValueChangeListener(this, getStoreProperty() + ".sessionDebug.level");
174
175     // tell the log manager to listen to these settings.
176
Pooka.getLogManager().addLogger(getStoreProperty());
177     Pooka.getLogManager().addLogger(getStoreProperty() + ".sessionDebug");
178
179     if (available) {
180       connectionListener = new ConnectionListener() {
181
182           public void disconnected(ConnectionEvent e) {
183             getLogger().log(Level.FINE, "Store " + getStoreID() + " disconnected.");
184             // if we think we're connected, then call disconnectStore.
185
if (isConnected()) {
186               try {
187                 if (Pooka.getUIFactory().getMessageNotificationManager() != null) {
188                   Pooka.getUIFactory().getMessageNotificationManager().displayMessage("Disconnected", "Disconnected from store " + getStoreID(), net.suberic.pooka.gui.MessageNotificationManager.WARNING_MESSAGE_TYPE);
189                 }
190                 disconnectStore();
191               } catch (MessagingException me) {
192                 getLogger().log(Level.FINE, "error disconnecting Store: " + me.getMessage());
193               }
194             }
195
196           }
197
198           public void closed(ConnectionEvent e) {
199             getLogger().log(Level.FINE, "Store " + getStoreID() + " closed.");
200
201             // if we think we're connected, then call disconnectStore.
202
if (isConnected()) {
203               if (Pooka.getUIFactory().getMessageNotificationManager() != null) {
204                 Pooka.getUIFactory().getMessageNotificationManager().displayMessage("Disconnected", "Disconnected from store " + getStoreID(), net.suberic.pooka.gui.MessageNotificationManager.WARNING_MESSAGE_TYPE);
205               }
206               try {
207                 disconnectStore();
208               } catch (MessagingException me) {
209                 getLogger().log(Level.FINE, "error disconnecting Store: " + me.getMessage());
210               }
211             }
212
213           }
214
215           public void opened(ConnectionEvent e) {
216             getLogger().log(Level.FINE, "Store " + getStoreID() + " opened.");
217           }
218         };
219
220       store.addConnectionListener(connectionListener);
221
222     }
223
224     if (storeThread == null) {
225       storeThread = new ActionThread(this.getStoreID() + " - ActionThread");
226       storeThread.start();
227     }
228
229     String JavaDoc defProfileString = Pooka.getProperty(getStoreProperty() + ".defaultProfile", "");
230     if (defProfileString.length() < 1 || defProfileString.equalsIgnoreCase(UserProfile.S_DEFAULT_PROFILE_KEY)) {
231       defaultProfile = null;
232     } else {
233       defaultProfile = Pooka.getPookaManager().getUserProfileManager().getProfile(defProfileString);
234     }
235
236     connection = Pooka.getConnectionManager().getConnection(Pooka.getProperty(getStoreProperty() + ".connection", ""));
237     if (connection == null) {
238       connection = Pooka.getConnectionManager().getDefaultConnection();
239     }
240
241     if (connection != null) {
242       connection.addConnectionListener(this);
243     }
244
245     updateChildren();
246
247     String JavaDoc trashFolderName = Pooka.getProperty(getStoreProperty() + ".trashFolder", "");
248     if (trashFolderName.length() > 0) {
249       trashFolder = getChild(trashFolderName);
250       if (trashFolder != null)
251         trashFolder.setTrashFolder(true);
252     }
253   }
254
255   /**
256    * This loads in the default session properties for this Store's
257    * Session.
258    */

259   public Properties loadProperties() {
260     Properties p = new Properties(System.getProperties());
261
262     String JavaDoc realProtocol = Pooka.getProperty("Store." + storeID + ".protocol", "");
263
264     if (realProtocol.equalsIgnoreCase("imap")) {
265       loadImapProperties(p);
266     } else if (realProtocol.equalsIgnoreCase("pop3")) {
267       loadPop3Properties(p);
268       String JavaDoc useMaildir = Pooka.getProperty(getStoreProperty() + ".useMaildir", "unset");
269
270       if (useMaildir.equals("unset")) {
271         Pooka.setProperty(getStoreProperty() + ".useMaildir", "false");
272         useMaildir="false";
273       }
274
275       if ( useMaildir.equalsIgnoreCase("false")) {
276         loadMboxProperties(p);
277       } else {
278         loadMaildirProperties(p);
279       }
280     } else if (realProtocol.equalsIgnoreCase("maildir")) {
281       loadMaildirProperties(p);
282     } else if (realProtocol.equalsIgnoreCase("mbox")) {
283       loadMboxProperties(p);
284     }
285     return p;
286   }
287
288   /**
289    * Load all IMAP properties.
290    */

291   void loadImapProperties(Properties p) {
292     p.setProperty("mail.imap.timeout", Pooka.getProperty(getStoreProperty() + ".timeout", Pooka.getProperty("Pooka.timeout", "-1")));
293     p.setProperty("mail.imap.connectiontimeout", Pooka.getProperty(getStoreProperty() + ".connectionTimeout", Pooka.getProperty("Pooka.connectionTimeout", "-1")));
294
295     p.setProperty("mail.imaps.timeout", Pooka.getProperty(getStoreProperty() + ".timeout", Pooka.getProperty("Pooka.timeout", "-1")));
296     p.setProperty("mail.imaps.connectiontimeout", Pooka.getProperty(getStoreProperty() + ".connectionTimeout", Pooka.getProperty("Pooka.connectionTimeout", "-1")));
297
298     // set up ssl
299
if (sslSetting.equals("ssl")) {
300       p.setProperty("mail.imaps.socketFactory.fallback", Pooka.getProperty(getStoreProperty() + ".SSL.fallback", "false"));
301     } else if (sslSetting.equals("tlsrequired")) {
302       p.setProperty("mail.imap.starttls.enable", "true");
303     } else if (sslSetting.equals("tls")) {
304       // failover is implemented in the connectStore() method.
305
p.setProperty("mail.imap.starttls.enable", "true");
306     }
307
308     // use a dedicated store connection.
309
p.setProperty("mail.imap.separatestoreconnection", "true");
310     p.setProperty("mail.imaps.separatestoreconnection", "true");
311   }
312
313   /**
314    * Load all POP3 properties.
315    */

316   void loadPop3Properties(Properties p) {
317     if (Pooka.getProperty(getStoreProperty() + ".SSL", "false").equalsIgnoreCase("true")) {
318       //p.setProperty("mail.pop3s.socketFactory.class", "net.suberic.pooka.ssl.PookaSSLSocketFactory");
319
p.setProperty("mail.pop3s.socketFactory.fallback", Pooka.getProperty(getStoreProperty() + ".SSL.fallback", "false"));
320       //p.setProperty("mail.pop3.socketFactory.port", Pooka.getProperty(getStoreProperty() + ".SSL.port", "995"));
321
}
322   }
323
324   /**
325    * Load all Maildir properties.
326    */

327   void loadMaildirProperties(Properties p) {
328
329     String JavaDoc mailHome = Pooka.getProperty(getStoreProperty() + ".mailDir", "");
330     if (mailHome.equals("")) {
331       mailHome = Pooka.getProperty("Pooka.defaultMailSubDir", "");
332       if (mailHome.equals(""))
333         mailHome = System.getProperty("user.home") + java.io.File.separator + ".pooka";
334
335       mailHome = mailHome + java.io.File.separator + storeID;
336     }
337
338     String JavaDoc userHomeName = mailHome + java.io.File.separator + Pooka.getProperty("Pooka.subFolderName", "folders");
339
340     //p.setProperty("mail.store.maildir.imapEmulation", "true");
341
p.setProperty("mail.store.maildir.baseDir", userHomeName);
342     p.setProperty("mail.store.maildir.autocreatedir", "true");
343   }
344
345   /**
346    * Load all Mbox properties.
347    */

348   void loadMboxProperties(Properties p) {
349     /*
350      * set the properties for mbox folders, and for the mbox backend of
351      * a pop3 mailbox. properties set are:
352      *
353      * mail.mbox.inbox: the location of the INBOX for this mail store. for
354      * pop3 stores, this is the location of the local copy of the inbox.
355      * for mbox stores, this should be the local inbox file.
356      * mail.mbox.userhome: the location of all subfolders.
357      */

358     String JavaDoc mailHome = Pooka.getProperty(getStoreProperty() + ".mailDir", "");
359     if (mailHome.equals("")) {
360       mailHome = Pooka.getProperty("Pooka.defaultMailSubDir", "");
361       if (mailHome.equals(""))
362         mailHome = System.getProperty("user.home") + java.io.File.separator + ".pooka";
363
364       mailHome = mailHome + java.io.File.separator + storeID;
365     }
366
367     String JavaDoc inboxFileName;
368     if (Pooka.getProperty(getStoreProperty() + ".protocol", "imap").equalsIgnoreCase("pop3")) {
369       inboxFileName = mailHome + java.io.File.separator + Pooka.getProperty("Pooka.inboxName", "INBOX");
370     } else {
371       inboxFileName = Pooka.getProperty(getStoreProperty() + ".inboxLocation", "/var/spool/mail/" + System.getProperty("user.name"));
372     }
373
374     String JavaDoc userHomeName = mailHome + java.io.File.separator + Pooka.getProperty("Pooka.subFolderName", "folders");
375
376     getLogger().log(Level.FINE, "for store " + getStoreID() + ", inboxFileName = " + inboxFileName + "; userhome = " + userHomeName);
377
378     p.setProperty("mail.mbox.inbox", inboxFileName);
379     p.setProperty("mail.mbox.userhome", userHomeName);
380   }
381
382   /**
383    * This updates the children of the current store. Generally called
384    * when the folderList property is changed.
385    */

386
387   public void updateChildren() {
388
389     Vector newChildren = new Vector();
390
391     StringTokenizer tokens = new StringTokenizer(Pooka.getProperty(getStoreProperty() + ".folderList", "INBOX"), ":");
392
393     getLogger().log(Level.FINE, "Pooka.getProperty(" + getStoreProperty() + ".folderList = " + Pooka.getProperty(getStoreProperty() + ".folderList"));
394
395     String JavaDoc newFolderName;
396
397     for (int i = 0 ; tokens.hasMoreTokens() ; i++) {
398       newFolderName = (String JavaDoc)tokens.nextToken();
399       FolderInfo childFolder = getChild(newFolderName);
400       if (childFolder == null) {
401         childFolder = Pooka.getResourceManager().createFolderInfo(this, newFolderName);
402       }
403
404       newChildren.add(childFolder);
405     }
406     children = newChildren;
407     getLogger().log(Level.FINE, getStoreID() + ": in configureStore. children.size() = " + children.size());
408
409     if (storeNode != null)
410       storeNode.loadChildren();
411   }
412
413   /**
414    * This goes through the list of children of this store and
415    * returns the FolderInfo for the given childName, if one exists.
416    * If none exists, or if the children Vector has not been loaded
417    * yet, or if this is a leaf node, then this method returns null.
418    */

419   public FolderInfo getChild(String JavaDoc childName) {
420     FolderInfo childFolder = null;
421     String JavaDoc folderName = null, subFolderName = null;
422
423     if (children != null) {
424       int divider = childName.indexOf('/');
425       if (divider > 0) {
426         folderName = childName.substring(0, divider);
427         if (divider < childName.length() - 1)
428           subFolderName = childName.substring(divider + 1);
429       } else
430         folderName = childName;
431
432       for (int i = 0; i < children.size(); i++)
433         if (((FolderInfo)children.elementAt(i)).getFolderName().equals(folderName))
434           childFolder = (FolderInfo)children.elementAt(i);
435     }
436
437     if (childFolder != null && subFolderName != null)
438       return childFolder.getChild(subFolderName);
439     else
440       return childFolder;
441   }
442
443
444   /**
445    * This goes through the list of children of this store and
446    * returns the FolderInfo that matches this folderID.
447    * If none exists, or if the children Vector has not been loaded
448    * yet, or if this is a leaf node, then this method returns null.
449    */

450   public FolderInfo getFolderById(String JavaDoc folderID) {
451     FolderInfo childFolder = null;
452
453     if (children != null) {
454       for (int i = 0; i < children.size(); i++) {
455         FolderInfo possibleMatch = ((FolderInfo)children.elementAt(i)).getFolderById(folderID);
456         if (possibleMatch != null) {
457           return possibleMatch;
458         }
459       }
460     }
461
462     return null;
463   }
464
465   /**
466    * This handles the event that the StoreInfo is removed from Pooka.
467    */

468   public void remove() {
469     // FIXME need to do a lot here.
470
try {
471       disconnectStore();
472     } catch (Exception JavaDoc e) {
473     }
474     cleanup();
475     // FIXME
476
// Pooka.getResources().removePropertyTree(getStoreProperty())
477

478   }
479
480   /**
481    * Cleans up all references to this StoreInfo.
482    */

483   public void cleanup() {
484     Pooka.getResources().removeValueChangeListener(this);
485     Pooka.getLogManager().removeLogger(getStoreProperty());
486
487     if (children != null && children.size() > 0) {
488       for (int i = 0; i < children.size(); i++)
489         ((FolderInfo)children.elementAt(i)).cleanup();
490     }
491
492     if (store != null) {
493       store.removeConnectionListener(connectionListener);
494     }
495     if (getStoreThread() != null) {
496       getStoreThread().setStop(true);
497     }
498   }
499
500   /**
501    * This handles the changes if the source property is modified.
502    *
503    * As defined in net.suberic.util.ValueChangeListener.
504    */

505
506   public void valueChanged(String JavaDoc pChangedValue) {
507     final String JavaDoc changedValue = pChangedValue;
508     javax.swing.AbstractAction JavaDoc valueChangedAction = new javax.swing.AbstractAction JavaDoc() {
509         public void actionPerformed(java.awt.event.ActionEvent JavaDoc ae) {
510           // check to make sure that we still exist.
511
List JavaDoc<String JavaDoc> storeList = Pooka.getResources().getPropertyAsList("Store", "");
512           if (storeList.contains(getStoreID())) {
513             if (changedValue.equals(getStoreProperty() + ".folderList")) {
514               updateChildren();
515             } else if (changedValue.equals(getStoreProperty() + ".defaultProfile")) {
516               String JavaDoc defProfileString = Pooka.getProperty(getStoreProperty() + ".defaultProfile", "");
517               if (defProfileString.length() < 1 || defProfileString.equalsIgnoreCase(UserProfile.S_DEFAULT_PROFILE_KEY)) {
518                 defaultProfile = null;
519               } else {
520                 defaultProfile = Pooka.getPookaManager().getUserProfileManager().getProfile(defProfileString);
521               }
522             } else if (changedValue.equals(getStoreProperty() + ".protocol") || changedValue.equals(getStoreProperty() + ".user") || changedValue.equals(getStoreProperty() + ".password") || changedValue.equals(getStoreProperty() + ".server") || changedValue.equals(getStoreProperty() + ".port") || changedValue.equals(getStoreProperty() + ".SSL") ) {
523
524               if (storeNode != null) {
525                 Enumeration childEnum = storeNode.children();
526                 Vector v = new Vector();
527                 while (childEnum.hasMoreElements())
528                   v.add(childEnum.nextElement());
529
530                 storeNode.removeChildren(v);
531               }
532
533               children = null;
534
535               try {
536                 disconnectStore();
537               } catch (Exception JavaDoc e) { }
538
539               getLogger().log(Level.FINE, "calling configureStore()");
540
541               configureStore();
542             } else if (changedValue.equals(getStoreProperty() + ".connection")) {
543               connection.removeConnectionListener(StoreInfo.this);
544
545               connection = Pooka.getConnectionManager().getConnection(Pooka.getProperty(getStoreProperty() + ".connection", ""));
546               if (connection == null) {
547                 connection = Pooka.getConnectionManager().getDefaultConnection();
548               }
549
550               if (connection != null) {
551                 connection.addConnectionListener(StoreInfo.this);
552               }
553             } else if (changedValue.equals(getStoreProperty() + ".useSubscribed")) {
554               useSubscribed = Pooka.getProperty(getStoreProperty() + ".useSubscribed", "false").equalsIgnoreCase("true");
555             } else if (changedValue.equals(getStoreProperty() + ".sessionDebug.level")) {
556               updateSessionDebug();
557             }
558           }
559         }
560       };
561
562     // if we don't do the update synchronously on the store thread,
563
// then subscribing to subfolders breaks.
564
java.awt.event.ActionEvent JavaDoc actionEvent = new java.awt.event.ActionEvent JavaDoc(this, 0, "value-changed");
565     if (Thread.currentThread() == getStoreThread()) {
566       valueChangedAction.actionPerformed(actionEvent);
567     } else {
568       getStoreThread().addToQueue(valueChangedAction, actionEvent);
569     }
570
571   }
572
573
574   /**
575    * Called when the status of the NetworkConnection changes.
576    */

577   public void connectionStatusChanged(NetworkConnection connection, int newStatus) {
578     // mbox folders still don't care.
579
if (! (protocol.equalsIgnoreCase("mbox") || protocol.equalsIgnoreCase("maildir"))) {
580       if (newStatus == NetworkConnection.CONNECTED) {
581         // we've connected.
582
// we probably don't care.
583

584       } else if (newStatus == NetworkConnection.DISCONNECTED) {
585         // we're being disconnected. close all the connections.
586
try {
587           disconnectStore();
588         } catch (MessagingException me) {
589           getLogger().log(Level.FINE, "Caught exception disconnecting Store " + getStoreID() + ": " + me);
590           if (getLogger().isLoggable(Level.FINE))
591             me.printStackTrace();
592           // else ignore
593
}
594
595       } else {
596         // we've been cut off. note it.
597
try {
598           disconnectStore();
599         } catch (MessagingException me) {
600           getLogger().log(Level.FINE, "Caught exception disconnecting Store " + getStoreID() + ": " + me);
601           if (getLogger().isLoggable(Level.FINE))
602             me.printStackTrace();
603           // else ignore
604
}
605       }
606     }
607   }
608   /**
609    * Remove the given String from the folderList property.
610    *
611    * Note that because this is also a ValueChangeListener to the
612    * folderList property, this will also result in the FolderInfo being
613    * removed from the children Vector.
614    */

615   void removeFromFolderList(String JavaDoc removeFolderName) {
616     Vector folderNames = Pooka.getResources().getPropertyAsVector(getStoreProperty() + ".folderList", "");
617
618     boolean first = true;
619     StringBuffer JavaDoc newValue = new StringBuffer JavaDoc();
620     String JavaDoc folderName;
621
622     for (int i = 0; i < folderNames.size(); i++) {
623       folderName = (String JavaDoc) folderNames.elementAt(i);
624
625       if (! folderName.equals(removeFolderName)) {
626         if (!first)
627           newValue.append(":");
628
629         newValue.append(folderName);
630         first = false;
631       }
632
633     }
634
635     Pooka.setProperty(getStoreProperty() + ".folderList", newValue.toString());
636   }
637
638   /**
639    * This adds the given folderString to the folderList property.
640    */

641   void addToFolderList(String JavaDoc addFolderName) {
642     String JavaDoc folderName;
643     Vector folderNames = Pooka.getResources().getPropertyAsVector(getStoreProperty() + ".folderList", "");
644
645     boolean found = false;
646
647     for (int i = 0; i < folderNames.size(); i++) {
648       folderName = (String JavaDoc) folderNames.elementAt(i);
649
650       if (folderName.equals(addFolderName)) {
651         found=true;
652       }
653
654     }
655
656     if (!found) {
657       String JavaDoc currentValue = Pooka.getProperty(getStoreProperty() + ".folderList");
658       if (currentValue.equals(""))
659         Pooka.setProperty(getStoreProperty() + ".folderList", addFolderName);
660       else
661         Pooka.setProperty(getStoreProperty() + ".folderList", currentValue + ":" + addFolderName);
662     }
663
664   }
665
666   /**
667    * This creates a folder if it doesn't exist already. If it does exist,
668    * but is not of the right type, or if there is a problem in creating the
669    * folder, throws an error.
670    */

671   public void createSubFolder(String JavaDoc subFolderName, int type) throws MessagingException {
672     Folder folder = store.getDefaultFolder();
673
674     if (folder != null) {
675       Folder subFolder = folder.getFolder(subFolderName);
676
677       if (subFolder == null) {
678         throw new MessagingException("Store returned null for subfolder " + subFolderName);
679       }
680
681       if (! subFolder.exists())
682         subFolder.create(type);
683
684       subscribeFolder(subFolderName);
685     } else {
686       throw new MessagingException("Failed to open store " + getStoreID() + " to create subfolder " + subFolderName);
687
688     }
689   }
690
691   /**
692    * This subscribes the Folder described by the given String to this
693    * StoreInfo.
694    */

695   public void subscribeFolder(String JavaDoc folderName) {
696     getLogger().log(Level.FINE, "subscribing folder " + folderName);
697
698     String JavaDoc subFolderName = null;
699     String JavaDoc childFolderName = null;
700     int firstSlash = folderName.indexOf('/');
701     while (firstSlash == 0) {
702       folderName = folderName.substring(1);
703       firstSlash = folderName.indexOf('/');
704     }
705
706     if (firstSlash > 0) {
707       childFolderName = folderName.substring(0, firstSlash);
708       if (firstSlash < folderName.length() -1)
709         subFolderName = folderName.substring(firstSlash +1);
710     } else
711       childFolderName = folderName;
712
713     getLogger().log(Level.FINE, "store " + getStoreID() + " subscribing folder " + childFolderName + "; sending " + subFolderName + " to child for subscription.");
714
715     this.addToFolderList(childFolderName);
716
717     FolderInfo childFolder = getChild(childFolderName);
718
719     getLogger().log(Level.FINE, "got child folder '" + childFolder + "' for " + childFolderName);
720
721     if (childFolder != null && subFolderName != null) {
722       childFolder.subscribeFolder(subFolderName);
723     }
724   }
725
726   /**
727    * This method connects the Store, and sets the StoreInfo to know that
728    * the Store should be connected. You should use this method instead of
729    * calling getStore().connect(), because if you use this method, then
730    * the StoreInfo will try to keep the Store connected, and will try to
731    * reconnect the Store if it gets disconnected before
732    * disconnectStore is called.
733    *
734    * This method also calls updateChildren() to load the children of
735    * the Store, if the children vector has not been loaded yet.
736    */

737   public void connectStore() throws MessagingException {
738     getLogger().log(Level.FINE, "trying to connect store " + getStoreID());
739
740     if (store.isConnected()) {
741       getLogger().log(Level.FINE, "store " + getStoreID() + " is already connected.");
742
743       connected=true;
744       return;
745     } else {
746       try {
747         // don't test for connections for mbox providers.
748
if (! (protocol.equalsIgnoreCase("mbox") || protocol.equalsIgnoreCase("maildir"))) {
749           NetworkConnection currentConnection = getConnection();
750           getLogger().log(Level.FINE, "connect store " + getStoreID() + ": checking connection.");
751
752           if (currentConnection != null) {
753             if (currentConnection.getStatus() == NetworkConnection.DISCONNECTED) {
754               getLogger().log(Level.FINE, "connect store " + getStoreID() + ": connection not up. trying to connect it..");
755
756               currentConnection.connect(true, true);
757             }
758
759             if (connection.getStatus() != NetworkConnection.CONNECTED) {
760               throw new MessagingException(Pooka.getProperty("error.connectionDown", "Connection down for Store: ") + getItemID());
761             } else {
762               getLogger().log(Level.FINE, "connect store " + getStoreID() + ": successfully opened connection.");
763
764             }
765           }
766         }
767
768         // Execute the precommand if there is one
769
String JavaDoc preCommand = Pooka.getProperty(getStoreProperty() + ".precommand", "");
770         if (preCommand.length() > 0) {
771           getLogger().log(Level.FINE, "connect store " + getStoreID() + ": executing precommand.");
772
773           try {
774             Process JavaDoc p = Runtime.getRuntime().exec(preCommand);
775             p.waitFor();
776           } catch (Exception JavaDoc ex) {
777             getLogger().log(Level.FINE, "Could not run precommand:");
778             ex.printStackTrace();
779           }
780         }
781
782         getLogger().log(Level.FINE, "connect store " + getStoreID() + ": doing store.connect()");
783         store.connect();
784       } catch (MessagingException me) {
785         Exception JavaDoc e = me.getNextException();
786
787         if (e != null && e instanceof java.io.InterruptedIOException JavaDoc)
788           store.connect();
789         else {
790           if (e != null && e.toString().contains("SunCertPathBuilderException") && "tls".equalsIgnoreCase(sslSetting)) {
791             // fall back.
792
Properties p = mSession.getProperties();
793             p.setProperty("mail.imap.starttls.enable", "false");
794
795             store = mSession.getStore(url);
796
797             store.connect();
798           } else {
799             throw me;
800           }
801         }
802       }
803
804       getLogger().log(Level.FINE, "connect store " + getStoreID() + ": connection succeeded; connected = true.");
805       connected=true;
806
807       if (useSubscribed && protocol.equalsIgnoreCase("imap")) {
808         synchSubscribed();
809       }
810
811       if (Pooka.getProperty("Pooka.openFoldersOnConnect", "true").equalsIgnoreCase("true")) {
812         for (int i = 0; i < children.size(); i++) {
813           doOpenFolders((FolderInfo) children.elementAt(i));
814         }
815       }
816     }
817   }
818
819   private void doOpenFolders(FolderInfo fi) {
820     if (Pooka.getProperty("Pooka.openFoldersInBackground", "false").equalsIgnoreCase("true")) {
821
822       final FolderInfo current = fi;
823       javax.swing.AbstractAction JavaDoc openFoldersAction = new javax.swing.AbstractAction JavaDoc() {
824           public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
825             current.openAllFolders(Folder.READ_WRITE);
826           }
827         };
828
829       openFoldersAction.putValue(javax.swing.Action.NAME, "file-open");
830       openFoldersAction.putValue(javax.swing.Action.SHORT_DESCRIPTION, "file-open on folder " + fi.getFolderID());
831       getStoreThread().addToQueue(openFoldersAction, new java.awt.event.ActionEvent JavaDoc(this, 0, "open-all"), ActionThread.PRIORITY_LOW);
832     }
833     else {
834       fi.openAllFolders(Folder.READ_WRITE);
835     }
836   }
837
838   /**
839    * This method disconnects the Store. If you connect to the Store using
840    * connectStore() (which you should), then you should use this method
841    * instead of calling getStore.disconnect(). If you don't, then the
842    * StoreInfo will try to reconnect the store.
843    */

844   public void disconnectStore() throws MessagingException {
845     getLogger().log(Level.FINE, "disconnecting store " + getStoreID());
846
847     MessagingException storeException = null;
848     if (!(store.isConnected())) {
849       connected=false;
850       closeAllFolders(false, false);
851       return;
852     } else {
853       try {
854         try {
855           closeAllFolders(false, false);
856         } catch (MessagingException folderMe) {
857           storeException = folderMe;
858         }
859         store.close();
860       } catch (MessagingException me) {
861         if (storeException != null) {
862           me.setNextException(storeException);
863         }
864         storeException = me;
865         throw storeException;
866       } finally {
867         connected=false;
868       }
869
870       if (storeException != null)
871         throw storeException;
872     }
873   }
874
875   /**
876    * Closes all of the Store's children.
877    */

878   public void closeAllFolders(boolean expunge, boolean shuttingDown) throws MessagingException {
879     if (getStoreThread() != null && ! getStoreThread().getStopped()) {
880       // if the store thread has exited, assume we're exiting, too.
881
synchronized(getStoreThread().getRunLock()) {
882         getLogger().log(Level.FINE, "closing all folders of store " + getStoreID());
883         Vector folders = getChildren();
884         if (folders != null) {
885           for (int i = 0; i < folders.size(); i++) {
886             ((FolderInfo) folders.elementAt(i)).closeAllFolders(expunge, shuttingDown);
887           }
888         }
889       }
890     }
891   }
892
893   /**
894    * Stops the store thread.
895    */

896   public void stopStoreThread() {
897     if (storeThread != null) {
898       storeThread.setStop(true);
899       //storeThread = null;
900
}
901   }
902
903   /**
904    * Gets all of the children folders of this StoreInfo which are both
905    * Open and can contain Messages.
906    */

907   public Vector getAllFolders() {
908     Vector returnValue = new Vector();
909     Vector subFolders = getChildren();
910     for (int i = 0; i < subFolders.size(); i++) {
911       returnValue.addAll(((FolderInfo) subFolders.elementAt(i)).getAllFolders());
912     }
913     return returnValue;
914   }
915
916   /**
917    * Synchronizes the locally stored subscribed folders list to the subscribed
918    * folder information from the IMAP server.
919    */

920   public void synchSubscribed() throws MessagingException {
921     // require the inbox. this is to work around a bug in which the inbox
922
// doesn't show up in certain conditions.
923

924     boolean foundInbox=false;
925
926     Folder[] subscribedFolders = store.getDefaultFolder().list();
927
928     StringBuffer JavaDoc newSubscribed = new StringBuffer JavaDoc();
929
930     ArrayList subscribedNames = new ArrayList();
931
932     for (int i = 0; subscribedFolders != null && i < subscribedFolders.length; i++) {
933       // sometimes listSubscribed() doesn't work.
934
// and sometimes list() returns duplicate entries for some reason.
935
String JavaDoc folderName = subscribedFolders[i].getName();
936       if (folderName.equalsIgnoreCase("inbox")) {
937         if (!foundInbox) {
938           foundInbox=true;
939           subscribedNames.add(folderName);
940         }
941       } else if (subscribedFolders[i].isSubscribed()) {
942         if (! subscribedNames.contains(folderName))
943           subscribedNames.add(folderName);
944       }
945     }
946
947     // add subscribed namespaces.
948
List JavaDoc tmpChildren = getChildren();
949     if (tmpChildren != null) {
950       // go through each. check to see if it's a namespace. if so,
951
// add it, too.
952

953       Iterator it = tmpChildren.iterator();
954       while (it.hasNext()) {
955         FolderInfo fi = (FolderInfo) it.next();
956         String JavaDoc folderName = fi.getFolderName();
957         if (fi.isNamespace() && ! subscribedNames.contains(folderName))
958           subscribedNames.add(folderName);
959       }
960     }
961
962     for (int i = 0; i < subscribedNames.size(); i++) {
963       newSubscribed.append((String JavaDoc)subscribedNames.get(i)).append(':');
964     }
965
966     if (newSubscribed.length() > 0)
967       newSubscribed.deleteCharAt(newSubscribed.length() -1);
968
969     // this will update our children vector.
970
Pooka.setProperty(getStoreProperty() + ".folderList", newSubscribed.toString());
971
972     for (int i = 0; children != null && i < children.size(); i++) {
973       FolderInfo fi = (FolderInfo) children.get(i);
974       fi.synchSubscribed();
975     }
976   }
977
978   // last connection check.
979
long lastConnectionCheck = 0;
980
981   /**
982    * Checks connection for this store.
983    */

984   public boolean checkConnection() {
985     // if we don't think we're connected, don't check.
986
if (! isConnected())
987       return false;
988
989     // don't check if we've checked very recently.
990
if (System.currentTimeMillis() - lastConnectionCheck > 20000) {
991       getLogger().log(Level.FINER, "Checking connection for store " + getStoreID());
992       Store realStore = getStore();
993
994       if (realStore != null) {
995         if (! realStore.isConnected()) {
996           getLogger().log(Level.FINER, getStoreID() + ": isConnected() returns false. returning false.");
997
998           return false;
999         } else {
1000          return true;
1001        }
1002      } else {
1003        return false;
1004      }
1005    } else {
1006      return isConnected();
1007    }
1008  }
1009
1010  /**
1011   * Shows the current status for this store and its thread.
1012   */

1013  public void showStatus() {
1014    StringBuffer JavaDoc statusBuffer = new StringBuffer JavaDoc();
1015    getLogger().log(Level.INFO, "Status for store " + getStoreID());
1016    statusBuffer.append("Status for store " + getStoreID() + "\r\n");
1017    boolean infoIsConnected = isConnected();
1018    getLogger().log(Level.INFO, "Connected: " + infoIsConnected);
1019    statusBuffer.append("Connected: " + infoIsConnected + "\r\n");
1020    /*
1021      if (store != null) {
1022      boolean storeIsConnected = store.isConnected();
1023      getLogger().log(Level.INFO, "store.isConnected(): " + storeIsConnected);
1024      statusBuffer.append("store.isConnected(): " + storeIsConnected + "\r\n");
1025      } else {
1026      getLogger().log(Level.INFO, "No store object.");
1027      }
1028    */

1029
1030    if (storeThread != null) {
1031      String JavaDoc currentAction = storeThread.getCurrentActionName();
1032      getLogger().log(Level.INFO, "Current Action: " + currentAction);
1033      statusBuffer.append("Current Action: " + currentAction + "\r\n");
1034      int queueSize = storeThread.getQueueSize();
1035      getLogger().log(Level.INFO, "Action Queue Size: " + queueSize);
1036      statusBuffer.append("Action Queue Size: " + queueSize +"\r\n");
1037      if (storeThread.getQueueSize() > 0) {
1038        System.out.println("Queue:");
1039        java.util.List JavaDoc queue = storeThread.getQueue();
1040        for (int i = 0; i < queue.size(); i++) {
1041          net.suberic.util.thread.ActionThread.ActionEventPair current = (net.suberic.util.thread.ActionThread.ActionEventPair) queue.get(i);
1042          String JavaDoc queueString = " queue[" + i + "]: ";
1043          String JavaDoc entryDescription = (String JavaDoc) current.action.getValue(javax.swing.Action.SHORT_DESCRIPTION);
1044          if (entryDescription == null)
1045            entryDescription = (String JavaDoc) current.action.getValue(javax.swing.Action.NAME);
1046          if (entryDescription == null)
1047            entryDescription = "Unknown action";
1048
1049          queueString = queueString + entryDescription;
1050          System.out.println(queueString);
1051          statusBuffer.append(queueString + "\r\n");
1052        }
1053      }
1054      statusBuffer.append("Stack Trace:\r\n");
1055      StackTraceElement JavaDoc[] stackTrace = storeThread.getStackTrace();
1056      for (StackTraceElement JavaDoc stackLine: stackTrace) {
1057        //System.out.println(stackLine);
1058
statusBuffer.append(" " + stackLine + "\r\n");
1059      }
1060
1061    } else {
1062      getLogger().log(Level.INFO, "No Action Thread.");
1063      StackTraceElement JavaDoc[] stackTrace = Thread.currentThread().getStackTrace();
1064      for (StackTraceElement JavaDoc stackLine: stackTrace) {
1065        //System.out.println(stackLine);
1066
statusBuffer.append(" " + stackLine + "\r\n");
1067      }
1068    }
1069
1070    Pooka.getUIFactory().showMessage(statusBuffer.toString(), "Status for " + getStoreID());
1071  }
1072
1073  // Accessor methods.
1074

1075  public Store getStore() {
1076    return store;
1077  }
1078
1079  private void setStore(Store newValue) {
1080    store=newValue;
1081  }
1082
1083  /**
1084   * This returns the StoreID.
1085   */

1086  public String JavaDoc getStoreID() {
1087    return storeID;
1088  }
1089
1090  /**
1091   * This returns the ItemID, which in this case is the StoreID.
1092   */

1093  public String JavaDoc getItemID() {
1094    return getStoreID();
1095  }
1096
1097  /**
1098   * This sets the storeID.
1099   */

1100  private void setStoreID(String JavaDoc newValue) {
1101    storeID=newValue;
1102  }
1103
1104  /**
1105   * This returns the property which defines this StoreInfo, such as
1106   * "Store.myStore".
1107   */

1108  public String JavaDoc getStoreProperty() {
1109    return "Store." + getStoreID();
1110  }
1111
1112  /**
1113   * This returns the item property, which in this case is the same as
1114   * the storeProperty.
1115   */

1116  public String JavaDoc getItemProperty() {
1117    return getStoreProperty();
1118  }
1119
1120  /**
1121   * Returns the protocol we're using.
1122   */

1123  public String JavaDoc getProtocol() {
1124    return protocol;
1125  }
1126
1127  /**
1128   * Returns true if this is a pop3 store.
1129   */

1130  public boolean isPopStore() {
1131    return popStore;
1132  }
1133
1134  public Vector getChildren() {
1135    return children;
1136  }
1137
1138  public StoreNode getStoreNode() {
1139    return storeNode;
1140  }
1141
1142  public void setStoreNode(StoreNode newValue) {
1143    storeNode = newValue;
1144  }
1145
1146  public boolean isConnected() {
1147    return connected;
1148  }
1149
1150  public boolean isAvailable() {
1151    return available;
1152  }
1153
1154  public boolean isAuthorized() {
1155    return authorized;
1156  }
1157
1158  public UserProfile getDefaultProfile() {
1159    return defaultProfile;
1160  }
1161
1162  public NetworkConnection getConnection() {
1163    return connection;
1164  }
1165
1166  public ActionThread getStoreThread() {
1167    return storeThread;
1168  }
1169
1170  public void setStoreThread(ActionThread newValue) {
1171    storeThread=newValue;
1172  }
1173
1174  public FolderInfo getTrashFolder() {
1175    return trashFolder;
1176  }
1177
1178  /**
1179   * This returns whether or not this Store is set up to use the
1180   * TrashFolder. If StoreProperty.useTrashFolder is set, return that as
1181   * a boolean. Otherwise, return Pooka.useTrashFolder as a boolean.
1182   */

1183  public boolean useTrashFolder() {
1184    if (getTrashFolder() == null)
1185      return false;
1186
1187    String JavaDoc prop = Pooka.getProperty(getStoreProperty() + ".useTrashFolder", "");
1188    if (!prop.equals(""))
1189      return (! prop.equalsIgnoreCase("false"));
1190    else
1191      return (! Pooka.getProperty("Pooka.useTrashFolder", "true").equalsIgnoreCase("true"));
1192
1193  }
1194
1195
1196  public void setTrashFolder(FolderInfo newValue) {
1197    trashFolder = newValue;
1198  }
1199
1200  /**
1201   * Returns the logger for this Store.
1202   */

1203  public Logger JavaDoc getLogger() {
1204    if (mLogger == null) {
1205      mLogger = Logger.getLogger(getStoreProperty());
1206    }
1207    return mLogger;
1208  }
1209
1210  /**
1211   * Updates the debug status on the session.
1212   */

1213  void updateSessionDebug() {
1214    if (Pooka.getProperty("Pooka.sessionDebug", "false").equalsIgnoreCase("true") || (! Pooka.getProperty(getStoreProperty() + ".sessionDebug.logLevel", "OFF").equalsIgnoreCase("OFF"))) {
1215      mSession.setDebug(true);
1216    } else {
1217      mSession.setDebug(false);
1218    }
1219  }
1220}
1221
Popular Tags