KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > mail > Mailbox


1 /*
2  * Mailbox.java
3  *
4  * Copyright (C) 2000-2003 Peter Graves
5  * $Id: Mailbox.java,v 1.6 2003/08/09 17:39:07 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j.mail;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.Comparator JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import javax.swing.Icon JavaDoc;
30 import javax.swing.SwingUtilities JavaDoc;
31 import org.armedbear.j.Buffer;
32 import org.armedbear.j.Debug;
33 import org.armedbear.j.Dispatcher;
34 import org.armedbear.j.Display;
35 import org.armedbear.j.Editor;
36 import org.armedbear.j.EditorIterator;
37 import org.armedbear.j.FastStringBuffer;
38 import org.armedbear.j.History;
39 import org.armedbear.j.InputDialog;
40 import org.armedbear.j.Line;
41 import org.armedbear.j.Log;
42 import org.armedbear.j.MessageDialog;
43 import org.armedbear.j.Position;
44 import org.armedbear.j.ProgressNotifier;
45 import org.armedbear.j.Property;
46 import org.armedbear.j.PropertyList;
47 import org.armedbear.j.Sidebar;
48 import org.armedbear.j.Utilities;
49 import org.armedbear.j.View;
50
51 public abstract class Mailbox extends Buffer
52 {
53     public static final int SORT_BY_DATE_SENT = 0;
54
55     protected MailboxURL url;
56
57     boolean showFullHeaders;
58     boolean showRawText;
59
60     protected boolean dirty;
61
62     protected int unreadMessageCount;
63     protected int newMessageCount;
64
65     protected List JavaDoc entries;
66
67     private long lastCheckMillis;
68
69     private int sortBy = SORT_BY_DATE_SENT;
70
71     private MessageBuffer previewBuffer;
72
73     protected Mailbox()
74     {
75     }
76
77     protected Mailbox(MailboxURL url)
78     {
79         this.url = url;
80         PropertyList props = MailboxProperties.getProperties(url);
81         if (props != null)
82             properties.putAll(props);
83     }
84
85     public MessageBuffer getPreviewBuffer()
86     {
87         return previewBuffer;
88     }
89
90     public void setPreviewBuffer(MessageBuffer buf)
91     {
92         previewBuffer = buf;
93     }
94
95     public Buffer getSecondary()
96     {
97         return previewBuffer;
98     }
99
100     public final MailboxURL getUrl()
101     {
102         return url;
103     }
104
105     public final int getSortBy()
106     {
107         return sortBy;
108     }
109
110     public abstract String JavaDoc getName();
111
112     public synchronized final void setEntries(List JavaDoc entries)
113     {
114         this.entries = entries;
115     }
116
117     public synchronized final long getLastCheckMillis()
118     {
119         return lastCheckMillis;
120     }
121
122     protected synchronized final void setLastCheckMillis(long when)
123     {
124         lastCheckMillis = when;
125     }
126
127     public synchronized long getLastErrorMillis()
128     {
129         return 0;
130     }
131
132     public abstract void getNewMessages();
133
134     public void getNewMessages(boolean userInitiated)
135     {
136     }
137
138     public abstract void readMessage(Line line);
139
140     public void readMessageOtherWindow(Line line)
141     {
142     }
143
144     protected void activateMessageBuffer(Editor editor,
145         MessageBuffer messageBuffer, boolean useOtherWindow)
146     {
147         editor.makeNext(messageBuffer);
148         if (useOtherWindow) {
149             Buffer oldBuffer = null;
150             Editor ed = editor.getOtherEditor();
151             if (ed != null)
152                 oldBuffer = ed.getBuffer();
153             messageBuffer.setTransient(true);
154             editor.activateInOtherWindow(messageBuffer,
155                                          messageBuffer.getSplit());
156             previewBuffer = messageBuffer;
157             if (oldBuffer != null && oldBuffer != messageBuffer) {
158                 if (oldBuffer.isTransient())
159                     oldBuffer.kill();
160             }
161         } else
162             editor.activate(messageBuffer);
163     }
164
165     public abstract void createFolder();
166     public abstract void deleteFolder();
167     public abstract void saveToFolder();
168     public abstract void moveToFolder();
169
170     public abstract void delete();
171
172     public abstract void undelete();
173
174     public abstract void markRead();
175
176     public abstract void markUnread();
177
178     public void flag()
179     {
180     }
181
182     public abstract void setAnsweredFlag(MailboxEntry entry);
183
184     public final int getUnreadMessageCount()
185     {
186         return unreadMessageCount;
187     }
188
189     public final int getNewMessageCount()
190     {
191         return newMessageCount;
192     }
193
194     // Count new and unread messages, respecting the limit that is in force
195
// (if any).
196
public void countMessages()
197     {
198         unreadMessageCount = newMessageCount = 0;
199         for (Line line = getFirstLine(); line != null; line = line.next()) {
200             if (line instanceof MailboxLine) {
201                 MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
202                 if (entry.isNew())
203                     ++newMessageCount;
204                 if (entry.isUnread())
205                     ++unreadMessageCount;
206             }
207         }
208     }
209
210     // Clear RECENT flag for all messages.
211
// Returns true if there was any change.
212
protected boolean clearRecent()
213     {
214         if (!isLocked())
215             Debug.bug("clearRecent mailbox not locked!");
216         boolean changed = false;
217         if (entries != null) {
218             final int size = entries.size();
219             for (int i = 0; i < size; i++) {
220                 MailboxEntry entry = (MailboxEntry) entries.get(i);
221                 if ((entry.getFlags() & MailboxEntry.RECENT) != 0) {
222                     entry.setFlags(entry.getFlags() & ~MailboxEntry.RECENT);
223                     changed = true;
224                 }
225             }
226         }
227         if (changed)
228             setDirty(true);
229         return changed;
230     }
231
232     public final void setDirty(boolean b)
233     {
234         dirty = b;
235     }
236
237     public final boolean isDirty()
238     {
239         return dirty;
240     }
241
242     public void tag(Editor editor, Line line)
243     {
244         if (line instanceof MailboxLine) {
245             MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
246             entry.toggleTag();
247             Editor.updateInAllEditors(line);
248             if (line.next() != null) {
249                 editor.getDot().setLine(line.next());
250                 editor.setMark(null);
251                 editor.moveDotToCaretCol();
252             }
253         }
254     }
255
256     public void tagPattern()
257     {
258         Editor editor = Editor.currentEditor();
259         InputDialog d = new InputDialog(editor, "Pattern:", "Tag Pattern", null);
260         d.setHistory(new History("mailboxTagPattern"));
261         editor.centerDialog(d);
262         d.show();
263         String JavaDoc pattern = d.getInput();
264         if (pattern == null)
265             return;
266         pattern = pattern.trim();
267         if (pattern.length() == 0)
268             return;
269         editor.repaintNow();
270         MailboxFilter filter = MailboxFilter.getMailboxFilter(pattern);
271         if (filter != null)
272             tag(filter);
273         else
274             MessageDialog.showMessageDialog("Bad pattern", "Tag Pattern");
275     }
276
277     private void tag(MailboxFilter filter)
278     {
279         Editor.currentEditor().setWaitCursor();
280         for (Line line = getFirstLine(); line != null; line = line.next()) {
281             if (line instanceof MailboxLine) {
282                 MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
283                 if (!entry.isTagged()) {
284                     if (filter.accept(entry)) {
285                         entry.tag();
286                         Editor.updateInAllEditors(line);
287                     }
288                 }
289             }
290         }
291     }
292
293     public void untagAll()
294     {
295         Editor.currentEditor().setWaitCursor();
296         for (Line line = getFirstLine(); line != null; line = line.next()) {
297             if (line instanceof MailboxLine) {
298                 MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
299                 if (entry.isTagged()) {
300                     entry.untag();
301                     Editor.updateInAllEditors(line);
302                 }
303             }
304         }
305     }
306
307     public void toggleRaw()
308     {
309         showRawText = !showRawText;
310         Editor.currentEditor().status("Raw mode " + (showRawText ? "on" : "off"));
311     }
312
313     public List JavaDoc getEntries()
314     {
315         return entries;
316     }
317
318     public List JavaDoc getTaggedEntries()
319     {
320         ArrayList JavaDoc taggedEntries = null;
321         final int size = entries.size();
322         for (int i = 0; i < size; i++) {
323             MailboxEntry entry = (MailboxEntry) entries.get(i);
324             if (entry.isTagged()) {
325                 if (taggedEntries == null)
326                     taggedEntries = new ArrayList JavaDoc();
327                 taggedEntries.add(entry);
328             }
329         }
330         return taggedEntries;
331     }
332
333     public MailboxEntry getEntryAtDot(Editor editor)
334     {
335         Line line = editor.getDotLine();
336         if (line instanceof MailboxLine)
337             return ((MailboxLine)line).getMailboxEntry();
338         else
339             return null;
340     }
341
342     public abstract void expunge();
343
344     public abstract int getMessageCount();
345
346     public Message getMessage(MailboxEntry entry, ProgressNotifier progressNotifier)
347     {
348         Debug.assertTrue(false);
349         return null;
350     }
351
352     public MailboxEntry getNextUndeleted(MailboxEntry entry)
353     {
354         Line line;
355         for (line = getFirstLine(); line != null; line = line.next()) {
356             if (line instanceof MailboxLine) {
357                 if (entry == ((MailboxLine)line).getMailboxEntry())
358                     break;
359             }
360         }
361         if (line != null) {
362             for (line = line.next(); line != null; line = line.next()) {
363                 if (line instanceof MailboxLine) {
364                     MailboxEntry maybe = ((MailboxLine)line).getMailboxEntry();
365                     if (!maybe.isDeleted())
366                         return maybe;
367                 }
368             }
369         }
370         return null;
371     }
372
373     public MailboxEntry getPreviousUndeleted(MailboxEntry entry)
374     {
375         Line line;
376         for (line = getFirstLine(); line != null; line = line.next()) {
377             if (line instanceof MailboxLine) {
378                 if (entry == ((MailboxLine)line).getMailboxEntry())
379                     break;
380             }
381         }
382         if (line != null) {
383             for (line = line.previous(); line != null; line = line.previous()) {
384                 if (line instanceof MailboxLine) {
385                     MailboxEntry maybe = ((MailboxLine)line).getMailboxEntry();
386                     if (!maybe.isDeleted())
387                         return maybe;
388                 }
389             }
390         }
391         return null;
392     }
393
394     public MailboxEntry getNextInThread(MailboxEntry entry)
395     {
396         String JavaDoc subject = entry.getSubject();
397         if (subject == null)
398             return null; // But there are other things we could try...
399
if (subject.toLowerCase().startsWith("re: "))
400             subject = subject.substring(4);
401         // Find current entry.
402
Line line;
403         for (line = getFirstLine(); line != null; line = line.next()) {
404             if (line instanceof MailboxLine)
405                 if (entry == ((MailboxLine)line).getMailboxEntry())
406                     break;
407         }
408         if (line != null) {
409             // Search later entries.
410
for (line = line.next(); line != null; line = line.next()) {
411                 if (line instanceof MailboxLine) {
412                     MailboxEntry maybe = ((MailboxLine)line).getMailboxEntry();
413                     // Note that we don't skip over deleted messages here.
414
String JavaDoc s = maybe.getSubject();
415                     if (s != null) {
416                         if (s.toLowerCase().startsWith("re: "))
417                             s = s.substring(4);
418                         if (s.equals(subject))
419                             return maybe;
420                     }
421                 }
422             }
423         }
424         return null;
425     }
426
427     public MailboxEntry getPreviousInThread(MailboxEntry entry)
428     {
429         String JavaDoc subject = entry.getSubject();
430         if (subject == null)
431             return null; // But there are other things we could try...
432
if (subject.toLowerCase().startsWith("re: "))
433             subject = subject.substring(4);
434         // Find current entry.
435
Line line;
436         for (line = getFirstLine(); line != null; line = line.next()) {
437             if (line instanceof MailboxLine)
438                 if (entry == ((MailboxLine)line).getMailboxEntry())
439                     break;
440         }
441         if (line != null) {
442             // Search earlier entries.
443
for (line = line.previous(); line != null; line = line.previous()) {
444                 if (line instanceof MailboxLine) {
445                     MailboxEntry maybe = ((MailboxLine)line).getMailboxEntry();
446                     // Note that we don't skip over deleted messages here.
447
String JavaDoc s = maybe.getSubject();
448                     if (s != null) {
449                         if (s.toLowerCase().startsWith("re: "))
450                             s = s.substring(4);
451                         if (s.equals(subject))
452                             return maybe;
453                     }
454                 }
455             }
456         }
457         return null;
458     }
459
460     public MailboxEntry getEntryForMessageId(String JavaDoc messageId)
461     {
462         if (messageId == null)
463             return null;
464         if (entries != null) {
465             for (int i = entries.size()-1; i >= 0; i--) {
466                 MailboxEntry entry = (MailboxEntry) entries.get(i);
467                 if (entry != null) {
468                     if (messageId.equals(entry.getMessageId()))
469                         return entry;
470                 }
471             }
472         }
473         return null;
474     }
475
476     public void bounce()
477     {
478         Debug.assertTrue(SwingUtilities.isEventDispatchThread());
479         final Editor editor = Editor.currentEditor();
480         List JavaDoc list = getTaggedEntries();
481         if (list == null) {
482             MailboxEntry entry = getEntryAtDot(editor);
483             if (entry == null)
484                 return;
485             list = new ArrayList JavaDoc(1);
486             list.add(entry);
487         }
488         final List JavaDoc toBeBounced = list;
489         // Get bounce addresses from user.
490
final MailAddress[] to = MailCommands.bounceGetTo(editor, toBeBounced.size());
491         if (to == null)
492             return;
493         Runnable JavaDoc bounceRunnable = new Runnable JavaDoc() {
494             public void run()
495             {
496                 boolean succeeded = false;
497                 try {
498                     succeeded = bounceMessages(toBeBounced, to);
499                 }
500                 finally {
501                     unlock();
502                     setBusy(false);
503                     editor.updateDisplayLater();
504                 }
505                 if (succeeded) {
506                     Runnable JavaDoc successRunnable = new Runnable JavaDoc() {
507                         public void run()
508                         {
509                             final int size = toBeBounced.size();
510                             FastStringBuffer sb = new FastStringBuffer(String.valueOf(size));
511                             sb.append(" message");
512                             if (size > 1)
513                                 sb.append('s');
514                             sb.append(" bounced");
515                             editor.status(sb.toString());
516                         }
517                     };
518                     SwingUtilities.invokeLater(successRunnable);
519                 } else {
520                     Runnable JavaDoc errorRunnable = new Runnable JavaDoc() {
521                         public void run()
522                         {
523                             MessageDialog.showMessageDialog(editor, "Failed", "Bounce");
524                         }
525                     };
526                     SwingUtilities.invokeLater(errorRunnable);
527                 }
528             }
529         };
530         if (lock()) {
531             setBusy(true);
532             new Thread JavaDoc(bounceRunnable).start();
533         } else
534             editor.status("Mailbox is locked");
535     }
536
537     private boolean bounceMessages(List JavaDoc toBeBounced, MailAddress[] to)
538     {
539         Log.debug("bounceMessages initializing SMTP session...");
540         SmtpSession smtp = SmtpSession.getDefaultSession();
541         if (smtp == null)
542             return false;
543         try {
544             for (int i = 0; i < toBeBounced.size(); i++) {
545                 MailboxEntry entry = (MailboxEntry) toBeBounced.get(i);
546                 if (!Mail.bounceMessage(getMessage(entry, null), to, smtp))
547                     return false;
548             }
549             return true;
550         }
551         finally {
552             Debug.assertTrue(smtp != null);
553             Log.debug("bounceMessages closing SMTP session...");
554             smtp.quit();
555         }
556     }
557
558     private String JavaDoc limitPattern;
559
560     public final String JavaDoc getLimitPattern()
561     {
562         return limitPattern;
563     }
564
565     public final void setLimitPattern(String JavaDoc pattern)
566     {
567         limitPattern = pattern;
568     }
569
570     public void limit()
571     {
572         Editor editor = Editor.currentEditor();
573         InputDialog d = new InputDialog(editor, "Pattern:", "Limit", limitPattern);
574         d.setHistory(new History("mailboxLimit"));
575         editor.centerDialog(d);
576         d.show();
577         String JavaDoc pattern = d.getInput();
578         if (pattern == null)
579             return; // No change (user cancelled input dialog).
580
editor.repaintNow();
581         pattern = pattern.trim();
582         if (pattern.length() == 0)
583             unlimit();
584         else {
585             MailboxFilter filter = MailboxFilter.getMailboxFilter(pattern);
586             if (filter != null) {
587                 if (lock()) {
588                     try {
589                         limitPattern = pattern;
590                         limit(filter);
591                     }
592                     finally {
593                         unlock();
594                     }
595                 } else
596                     editor.status("Mailbox is locked");
597             } else
598                 MessageDialog.showMessageDialog("Bad limit pattern", "Limit");
599         }
600     }
601
602     public void unlimit()
603     {
604         if (lock()) {
605             try {
606                 limitPattern = null;
607                 limit(null);
608             }
609             finally {
610                 unlock();
611             }
612         } else
613             Editor.currentEditor().status("Mailbox is locked");
614     }
615
616     // The limit filter that's currently in effect.
617
private MailboxFilter limitFilter;
618
619     public final MailboxFilter getLimitFilter()
620     {
621         return limitFilter;
622     }
623
624     public final void setLimitFilter(MailboxFilter filter)
625     {
626         limitFilter = filter;
627     }
628
629     public void limit(MailboxFilter filter)
630     {
631         Debug.assertTrue(SwingUtilities.isEventDispatchThread());
632         final Editor editor = Editor.currentEditor();
633         editor.repaintNow();
634         editor.setWaitCursor();
635         // Remember where we are.
636
MailboxEntry currentEntry = null;
637         if (editor.getDot() != null && editor.getDotLine() instanceof MailboxLine)
638             currentEntry = ((MailboxLine)editor.getDotLine()).getMailboxEntry();
639         limitFilter = filter;
640         refreshBuffer();
641         // Update message count in sidebar buffer list.
642
Sidebar.repaintBufferListInAllFrames();
643         Line dotLine = null;
644         if (getFirstLine() != null) {
645             dotLine = getFirstLine();
646             if (currentEntry != null) {
647                 boolean groupByThread =
648                     getBooleanProperty(Property.GROUP_BY_THREAD);
649                 for (Line line = getFirstLine(); line != null; line = line.next()) {
650                     MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
651                     if (entry == currentEntry) {
652                         dotLine = line;
653                         break;
654                     }
655                     if (!groupByThread) {
656                         if (RFC822Date.compare(entry.getDate(), currentEntry.getDate()) < 0)
657                             dotLine = line;
658                         else
659                             break;
660                     }
661                 }
662             }
663         }
664         invalidate();
665         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
666             Editor ed = it.nextEditor();
667             if (ed.getBuffer() == this) {
668                 ed.updateLocation();
669                 Display display = ed.getDisplay();
670                 if (dotLine != null) {
671                     ed.setDot(dotLine, 0);
672                     display.moveCaretToDotCol();
673                     ed.setMark(null);
674                     display.setTopLine(getFirstLine());
675                     display.setUpdateFlag(REPAINT);
676                 } else {
677                     ed.setDot(null);
678                     ed.setMark(null);
679                     display.setTopLine(null);
680                 }
681                 ed.updateDisplay();
682             }
683         }
684         editor.setDefaultCursor();
685     }
686
687     public MailboxLine getLineForEntry(MailboxEntry entry)
688     {
689         if (entry != null) {
690             for (Line line = getFirstLine(); line != null; line = line.next()) {
691                 if (line instanceof MailboxLine)
692                     if (((MailboxLine)line).getMailboxEntry() == entry)
693                         return (MailboxLine)line;
694             }
695         }
696         return null;
697     }
698
699     public MailboxLine findLineForEntry(MailboxEntry entry)
700     {
701         if (entry != null) {
702             // First look through all the entries for an exact match.
703
for (Line l = getFirstLine(); l != null; l = l.next()) {
704                 MailboxLine line = (MailboxLine) l;
705                 MailboxEntry e = line.getMailboxEntry();
706                 if (e == entry)
707                     return line;
708             }
709             // We didn't find an exact match.
710
boolean groupByThread =
711                 getBooleanProperty(Property.GROUP_BY_THREAD);
712             for (Line l = getFirstLine(); l != null; l = l.next()) {
713                 if (l instanceof MailboxLine) {
714                     MailboxLine line = (MailboxLine) l;
715                     MailboxEntry e = line.getMailboxEntry();
716                     // Only check date and size.
717
if (e.getDate().equals(entry.getDate())) {
718                         if (e.getSize() == entry.getSize()) {
719                             // Found it!
720
Log.debug("findLineForEntry date/size match");
721                             return line;
722                         }
723                     } else if (!groupByThread) {
724                         if (RFC822Date.compare(e.getDate(), entry.getDate()) > 0) {
725                             // We're past it (assuming mailbox is sorted by date).
726
// The entry we're looking for was deleted. Return the
727
// current line.
728
return line;
729                         }
730                     } else if (line.next() == null) {
731                         // Last line of mailbox.
732
return line;
733                     }
734                 }
735             }
736         }
737         return null;
738     }
739
740     public int getLineNumberForEntry(MailboxEntry entry)
741     {
742         Line line = getLineForEntry(entry);
743         if (line != null)
744             return line.lineNumber();
745         else
746             return -1;
747     }
748
749     // Find first message that's not seen and not deleted.
750
public Position getInitialDotPos()
751     {
752         if (getFirstLine() == null)
753             return null;
754         Line line = getFirstLine();
755         while (true) {
756             if (line instanceof MailboxLine) {
757                 MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
758                 if (entry != null) {
759                     int flags = entry.getFlags();
760                     if ((flags & MailboxEntry.SEEN) == 0)
761                         if ((flags & MailboxEntry.DELETED) == 0)
762                             return new Position(line, 0);
763                 }
764             }
765             if (line.next() == null)
766                 break; // Reached last line.
767
line = line.next();
768         }
769         return new Position(line, 0);
770     }
771
772     public MailboxEntry getInitialEntry()
773     {
774         if (getFirstLine() == null)
775             return null;
776         Line line = getFirstLine();
777         while (true) {
778             if (line instanceof MailboxLine) {
779                 MailboxEntry entry = ((MailboxLine)line).getMailboxEntry();
780                 if (entry != null) {
781                     int flags = entry.getFlags();
782                     if ((flags & MailboxEntry.SEEN) == 0)
783                         if ((flags & MailboxEntry.DELETED) == 0)
784                             return entry;
785                 }
786             }
787             if (line.next() == null)
788                 break; // Reached last line.
789
line = line.next();
790         }
791         return ((MailboxLine)line).getMailboxEntry();
792     }
793
794     public void updateEntry(MailboxEntry entry)
795     {
796         MailboxLine line = getLineForEntry(entry);
797         if (line != null) {
798             line.setText(entry.toString(line.getDepth()));
799             Editor.updateInAllEditors(this, line);
800         }
801     }
802
803     public final void toggleGroupByThread()
804     {
805         boolean groupByThread = getBooleanProperty(Property.GROUP_BY_THREAD);
806         setProperty(Property.GROUP_BY_THREAD, !groupByThread);
807         sort();
808     }
809
810     private void sort()
811     {
812         final Editor editor = Editor.currentEditor();
813         // Remember where we are.
814
final MailboxEntry currentEntry;
815         if (editor.getDot() != null && editor.getDotLine() instanceof MailboxLine)
816             currentEntry = ((MailboxLine)editor.getDotLine()).getMailboxEntry();
817         else
818             currentEntry = null;
819         final Runnable JavaDoc completionRunnable = new Runnable JavaDoc() {
820             public void run()
821             {
822                 for (EditorIterator it = new EditorIterator(); it.hasNext();) {
823                     Editor ed = it.nextEditor();
824                     View view = new View();
825                     view.setDotEntry(currentEntry != null ? currentEntry : getInitialEntry());
826                     ed.setView(Mailbox.this, view);
827                     if (ed.getBuffer() == Mailbox.this) {
828                         ed.bufferActivated(true);
829                         ed.updateDisplay();
830                     }
831                 }
832             }
833         };
834         Runnable JavaDoc sortRunnable = new Runnable JavaDoc() {
835             public void run()
836             {
837                 editor.setWaitCursor();
838                 try {
839                     refreshBuffer();
840                     SwingUtilities.invokeLater(completionRunnable);
841                 }
842                 finally {
843                     unlock();
844                     setBusy(false);
845                     editor.setDefaultCursor();
846                 }
847             }
848         };
849         if (lock()) {
850             setBusy(true);
851             new Thread JavaDoc(sortRunnable).start();
852         }
853     }
854
855     public void foldThread(Line line)
856     {
857         if (!getBooleanProperty(Property.GROUP_BY_THREAD))
858             return;
859         if (line instanceof MailboxLine) {
860             MailboxLine begin = (MailboxLine) line;
861             // Find start of thread.
862
while (begin.getDepth() > 1) {
863                 Line prev = begin.previous();
864                 if (prev instanceof MailboxLine)
865                     begin = (MailboxLine) prev;
866                 else
867                     break;
868             }
869             if (begin.next() instanceof MailboxLine) {
870                 MailboxLine end = (MailboxLine) begin.next();
871                 while (end.getDepth() > 1) {
872                     Line next = end.next();
873                     if (next instanceof MailboxLine)
874                         end = (MailboxLine) next;
875                     else
876                         break;
877                 }
878                 for (Line toBeHidden = begin.next(); toBeHidden != end && toBeHidden != null; toBeHidden = toBeHidden.next())
879                     toBeHidden.hide();
880                 renumber();
881                 Editor.unhideDotInAllFrames(this);
882             }
883         }
884     }
885
886     public void foldThreads()
887     {
888         if (!getBooleanProperty(Property.GROUP_BY_THREAD))
889             return;
890         for (Line line = getFirstLine(); line != null; line = line.nextVisible()) {
891             if (line instanceof MailboxLine) {
892                 MailboxLine begin = (MailboxLine) line;
893                 if (begin.getDepth() == 1) {
894                     if (begin.next() instanceof MailboxLine) {
895                         MailboxLine end = (MailboxLine) begin.next();
896                         while (end.getDepth() > 1) {
897                             Line next = end.next();
898                             if (next instanceof MailboxLine)
899                                 end = (MailboxLine) next;
900                             else
901                                 break;
902                         }
903                         for (Line toBeHidden = begin.next(); toBeHidden != end && toBeHidden != null; toBeHidden = toBeHidden.next())
904                             toBeHidden.hide();
905                     }
906                 }
907             }
908         }
909         renumber();
910         Editor.unhideDotInAllFrames(this);
911     }
912
913     protected void refreshBuffer()
914     {
915         if (getBooleanProperty(Property.GROUP_BY_THREAD)) {
916             long start = System.currentTimeMillis();
917             SortByThread sort = new SortByThread(entries);
918             sort.run();
919             try {
920                 lockWrite();
921             }
922             catch (InterruptedException JavaDoc e) {
923                 Log.error(e);
924                 return;
925             }
926             try {
927                 synchronized (this) {
928                     empty();
929                     sort.addEntries(this, limitFilter);
930                     renumber();
931                     countMessages();
932                     setLoaded(true);
933                 }
934             }
935             finally {
936                 unlockWrite();
937             }
938             long elapsed = System.currentTimeMillis() - start;
939             Log.debug("refreshBuffer " + elapsed + " ms");
940         } else {
941             Debug.assertTrue(sortBy == SORT_BY_DATE_SENT);
942             // Don't change order of entries!
943
ArrayList JavaDoc temp = new ArrayList JavaDoc(entries);
944             sortEntriesByDate(temp);
945             List JavaDoc matchingEntries = getMatchingEntries(temp, limitFilter);
946             try {
947                 lockWrite();
948             }
949             catch (InterruptedException JavaDoc e) {
950                 Log.error(e);
951                 return;
952             }
953             try {
954                 synchronized (this) {
955                     empty();
956                     final int size = matchingEntries.size();
957                     for (int i = 0; i < size; i++)
958                         appendLine(((MailboxEntry)matchingEntries.get(i)));
959                     renumber();
960                     countMessages();
961                     setLoaded(true);
962                 }
963             }
964             finally {
965                 unlockWrite();
966             }
967         }
968     }
969
970     // Never returns null.
971
private static List JavaDoc getMatchingEntries(List JavaDoc list, MailboxFilter filter)
972     {
973         if (list == null)
974             return new ArrayList JavaDoc();
975         if (filter == null)
976             return new ArrayList JavaDoc(list);
977         ArrayList JavaDoc matchingEntries = new ArrayList JavaDoc();
978         final int size = list.size();
979         for (int i = 0; i < size; i++) {
980             MailboxEntry entry = (MailboxEntry) list.get(i);
981             if (filter.accept(entry))
982                 matchingEntries.add(entry);
983         }
984         return matchingEntries;
985     }
986
987     public final void appendLine(MailboxEntry entry)
988     {
989         appendLine(new MailboxLine(entry));
990     }
991
992     public final void appendLine(MailboxEntry entry, int depth)
993     {
994         appendLine(new MailboxLine(entry, depth));
995     }
996
997     private static void sortEntriesByDate(List JavaDoc list)
998     {
999         Comparator JavaDoc c = new Comparator JavaDoc() {
1000            public int compare(Object JavaDoc o1, Object JavaDoc o2)
1001            {
1002                return RFC822Date.compare(((MailboxEntry)o1).getDate(),
1003                    ((MailboxEntry)o2).getDate());
1004            }
1005        };
1006        Collections.sort(list, c);
1007        int sequenceNumber = 1;
1008        Iterator JavaDoc iter = list.iterator();
1009        while (iter.hasNext()) {
1010            MailboxEntry entry = (MailboxEntry) iter.next();
1011            entry.setSequenceNumber(sequenceNumber++);
1012        }
1013    }
1014
1015    protected void addEntriesToAddressBook(List JavaDoc list)
1016    {
1017        if (list == null)
1018            return;
1019        MailAddress userMailAddress = Mail.getUserMailAddress();
1020        AddressBook addressBook = AddressBook.getGlobalAddressBook();
1021        for (int i = 0; i < list.size(); i++) {
1022            MailboxEntry sourceEntry = (MailboxEntry) list.get(i);
1023            int flags = sourceEntry.getFlags();
1024            if ((flags & MailboxEntry.DELETED) != 0)
1025                continue;
1026            MailAddress[] from = sourceEntry.getFrom();
1027            MailAddress[] to = sourceEntry.getTo();
1028            MailAddress[] cc = sourceEntry.getCc();
1029            boolean add = false;
1030            if ((flags & MailboxEntry.ANSWERED) != 0) {
1031                // I replied to this message.
1032
add = true;
1033            } else if (from != null) {
1034                for (int j = 0; j < from.length; j++) {
1035                    MailAddress a = from[j];
1036                    if (a.matches(userMailAddress)) {
1037                        // Message is from me.
1038
add = true;
1039                        break;
1040                    }
1041                }
1042            }
1043            if (!add) {
1044                if (to != null) {
1045                    for (int j = 0; j < to.length; j++) {
1046                        MailAddress a = to[j];
1047                        if (a.matches(userMailAddress)) {
1048                            // Message to me.
1049
add = true;
1050                            break;
1051                        }
1052                    }
1053                }
1054                if (!add && cc != null) {
1055                    for (int j = 0; j < cc.length; j++) {
1056                        MailAddress a = cc[j];
1057                        if (a.matches(userMailAddress)) {
1058                            // Message copied to me.
1059
add = true;
1060                            break;
1061                        }
1062                    }
1063                }
1064            }
1065            if (add) {
1066                if (to != null)
1067                    for (int j = 0; j < to.length; j++)
1068                        addressBook.maybeAddMailAddress(to[j]);
1069                if (cc != null)
1070                    for (int j = 0; j < cc.length; j++)
1071                        addressBook.maybeAddMailAddress(cc[j]);
1072                if (from != null)
1073                    for (int j = 0; j < from.length; j++)
1074                        addressBook.maybeAddMailAddress(from[j]);
1075            }
1076        }
1077        AddressBook.saveGlobalAddressBook();
1078    }
1079
1080    // For the buffer list.
1081
public Icon JavaDoc getIcon()
1082    {
1083        return Utilities.getIconFromFile(newMessageCount > 0 ? "mailbox_new.png" : "mailbox.png");
1084    }
1085
1086    public String JavaDoc getFileNameForDisplay()
1087    {
1088        return "";
1089    }
1090
1091    protected void newMessagesStatus()
1092    {
1093        if (newMessageCount > 0) {
1094            FastStringBuffer sb = new FastStringBuffer(32);
1095            sb.append(String.valueOf(newMessageCount));
1096            sb.append(" new message");
1097            if (newMessageCount > 1)
1098                sb.append('s');
1099            status(sb.toString());
1100        } else
1101            status("No new messages");
1102    }
1103
1104    protected void status(final String JavaDoc s)
1105    {
1106        Runnable JavaDoc r = new Runnable JavaDoc() {
1107            public void run()
1108            {
1109                for (int i = 0; i < Editor.getFrameCount(); i++) {
1110                    Editor ed = Editor.getFrame(i).getCurrentEditor();
1111                    if (ed.getBuffer() == Mailbox.this)
1112                        ed.status(s);
1113                }
1114            }
1115        };
1116        SwingUtilities.invokeLater(r);
1117    }
1118
1119    public MailAddress getUserMailAddress()
1120    {
1121        String JavaDoc address = getStringProperty(Property.USER_MAIL_ADDRESS);
1122        if (address == null)
1123            return null;
1124        return new MailAddress(getStringProperty(Property.USER_FULL_NAME), address);
1125    }
1126
1127    public boolean isChildVisible()
1128    {
1129        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1130            Buffer buffer = it.nextEditor().getBuffer();
1131            if (buffer instanceof MessageBuffer)
1132                if (((MessageBuffer)buffer).getMailbox() == this)
1133                    return true;
1134        }
1135        return false;
1136    }
1137
1138    // Returns true if mailbox has been idle for the specified number of
1139
// seconds, depending on whether it's in the foreground or background.
1140
public boolean isIdle(int fg, int bg)
1141    {
1142        if (!isVisible() && !isChildVisible()) {
1143            // Mailbox is in the background.
1144
if (bg == 0)
1145                return false;
1146            else if (System.currentTimeMillis() - Dispatcher.getLastEventMillis() > bg * 1000)
1147                return true;
1148            else
1149                return false;
1150        } else {
1151            // Mailbox (or one of its messages) is in the foreground.
1152
if (fg == 0)
1153                return false;
1154            else if (System.currentTimeMillis() - Dispatcher.getLastEventMillis() > fg * 1000)
1155                return true;
1156            else
1157                return false;
1158        }
1159    }
1160
1161    protected void error(final String JavaDoc text, final String JavaDoc title)
1162    {
1163        Runnable JavaDoc r = new Runnable JavaDoc() {
1164            public void run()
1165            {
1166                Editor editor = Editor.currentEditor();
1167                // Restore default cursor.
1168
setBusy(false);
1169                editor.updateDisplay();
1170                MessageDialog.showMessageDialog(editor, text, title);
1171            }
1172        };
1173        SwingUtilities.invokeLater(r);
1174    }
1175
1176    protected void success(final String JavaDoc text)
1177    {
1178        Runnable JavaDoc r = new Runnable JavaDoc() {
1179            public void run()
1180            {
1181                Editor.currentEditor().status(text);
1182            }
1183        };
1184        SwingUtilities.invokeLater(r);
1185    }
1186
1187    protected void saveDisplayState()
1188    {
1189        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1190            Editor ed = it.nextEditor();
1191            if (ed.getBuffer() == this)
1192                ed.saveView();
1193        }
1194    }
1195
1196    protected void updateDisplay()
1197    {
1198        SwingUtilities.invokeLater(updateDisplayRunnable);
1199    }
1200
1201    private Runnable JavaDoc updateDisplayRunnable = new Runnable JavaDoc() {
1202        public void run()
1203        {
1204            invalidate();
1205            for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1206                Editor ed = it.nextEditor();
1207                if (ed.getBuffer() == Mailbox.this) {
1208                    View view = ed.getView(ed.getBuffer());
1209                    if (view.getDotEntry() != null) {
1210                        try {
1211                            lockRead();
1212                        }
1213                        catch (InterruptedException JavaDoc e) {
1214                            Log.error(e);
1215                            return;
1216                        }
1217                        try {
1218                            Line topLine = findLineForEntry(view.getTopEntry());
1219                            if (topLine == null)
1220                                topLine = getFirstLine();
1221                            ed.setTopLine(topLine);
1222                            Line dotLine = findLineForEntry(view.getDotEntry());
1223                            if (dotLine != null) {
1224                                int offset = view.getDotOffset();
1225                                if (offset > dotLine.length())
1226                                    offset = dotLine.length();
1227                                ed.setDot(dotLine, offset);
1228                                ed.moveCaretToDotCol();
1229                            } else {
1230                                dotLine = getLastLine();
1231                                if (dotLine != null) {
1232                                    Log.debug("updateDisplayRunnable setting dotLine to last line");
1233                                    ed.setDot(dotLine, 0);
1234                                    ed.moveCaretToDotCol();
1235                                } else
1236                                    ed.setDot(null);
1237                            }
1238                            ed.setMark(null);
1239                        }
1240                        finally {
1241                            unlockRead();
1242                        }
1243                    } else {
1244                        Line firstLine = getFirstLine();
1245                        if (firstLine != null) {
1246                            ed.setDot(firstLine, 0);
1247                            ed.moveCaretToDotCol();
1248                            ed.setMark(null);
1249                            ed.setTopLine(firstLine);
1250                        } else {
1251                            ed.setDot(null);
1252                            ed.setMark(null);
1253                            ed.setTopLine(null);
1254                        }
1255                    }
1256                    ed.setUpdateFlag(REPAINT);
1257                    ed.updateDisplay();
1258                }
1259            }
1260            Sidebar.setUpdateFlagInAllFrames(SIDEBAR_BUFFER_LIST_CHANGED);
1261            Sidebar.repaintBufferListInAllFrames();
1262        }
1263    };
1264
1265    protected void advanceDot(final Line dotLine)
1266    {
1267        final Line nextLine = dotLine.next();
1268        if (nextLine != null)
1269            setDotLine(nextLine);
1270    }
1271
1272    public void setDotEntry(MailboxEntry entry)
1273    {
1274        final MailboxLine line = findLineForEntry(entry);
1275        if (line != null && line.getMailboxEntry() == entry)
1276            setDotLine(line);
1277    }
1278
1279    private void setDotLine(final Line line)
1280    {
1281        Runnable JavaDoc r = new Runnable JavaDoc() {
1282            public void run()
1283            {
1284                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1285                    Editor ed = it.nextEditor();
1286                    if (ed.getBuffer() == Mailbox.this) {
1287                        if (ed.getDot() != null) {
1288                            ed.update(ed.getDotLine());
1289                            ed.getDot().moveTo(line, 0);
1290                            ed.update(line);
1291                            ed.moveCaretToDotCol();
1292                            ed.clearStatusText();
1293                            ed.updateDisplay();
1294                        }
1295                    }
1296                }
1297            }
1298        };
1299        if (SwingUtilities.isEventDispatchThread())
1300            r.run();
1301        else
1302            SwingUtilities.invokeLater(r);
1303    }
1304
1305    public String JavaDoc getStatusText(Editor editor)
1306    {
1307        FastStringBuffer sb = new FastStringBuffer();
1308        if (editor.getDot() != null) {
1309            sb.append("Message ");
1310            sb.append(String.valueOf(editor.getDotLineNumber()+1));
1311            sb.append(" of ");
1312            sb.append(String.valueOf(getLineCount()));
1313            final int u = getUnreadMessageCount();
1314            if (u > 0) {
1315                final int n = getNewMessageCount();
1316                sb.append(" (");
1317                if (n > 0) {
1318                    sb.append(n);
1319                    sb.append(" new, ");
1320                }
1321                sb.append(u);
1322                sb.append(" unread)");
1323            }
1324        } else {
1325            sb.append("No messages");
1326        }
1327        return sb.toString();
1328    }
1329
1330    public void saveView(Editor editor)
1331    {
1332        final View view = saveViewInternal(editor);
1333        final Line topLine = editor.getTopLine();
1334        if (topLine instanceof MailboxLine)
1335            view.setTopEntry(((MailboxLine)topLine).getMailboxEntry());
1336        if (editor.getDot() != null) {
1337            Line dotLine = editor.getDotLine();
1338            if (dotLine instanceof MailboxLine)
1339                view.setDotEntry(((MailboxLine)dotLine).getMailboxEntry());
1340        }
1341        editor.setView(this, view);
1342        setLastView(view);
1343    }
1344
1345    public void restoreView(Editor editor)
1346    {
1347        final Display display = editor.getDisplay();
1348        final View view = editor.getView(this);
1349        Debug.assertTrue(view != null);
1350        if (view != null) {
1351            if (view.getDotEntry() == null) {
1352                super.restoreView(editor);
1353                return;
1354            }
1355            Line topLine = findLineForEntry(view.getTopEntry());
1356            if (topLine == null)
1357                topLine = getFirstLine();
1358            display.setTopLine(topLine);
1359            Line dotLine = findLineForEntry(view.getDotEntry());
1360            if (dotLine == null)
1361                dotLine = getFirstLine();
1362            if (view.getTopLine() == topLine && view.getDot() != null && view.getDot().getLine() == dotLine) {
1363                editor.setDot(new Position(view.getDot()));
1364                editor.setMark(view.getMark() == null ? null : new Position(view.getMark()));
1365                editor.setSelection(view.getSelection());
1366                display.setTopLine(view.getTopLine());
1367                display.setShift(view.getShift());
1368                display.setCaretCol(view.getCaretCol());
1369            } else {
1370                editor.setDot(dotLine != null ? new Position(dotLine, 0) : null);
1371                editor.moveCaretToDotCol();
1372                editor.setMark(null);
1373            }
1374        }
1375    }
1376
1377    protected void notImplemented(String JavaDoc s)
1378    {
1379        Log.error(s.concat(" is not implemented"));
1380    }
1381}
1382
Popular Tags