KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > mail > folder > imap > IMAPFolder


1 // The contents of this file are subject to the Mozilla Public License Version
2
// 1.1
3
//(the "License"); you may not use this file except in compliance with the
4
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
5
//
6
//Software distributed under the License is distributed on an "AS IS" basis,
7
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8
//for the specific language governing rights and
9
//limitations under the License.
10
//
11
//The Original Code is "The Columba Project"
12
//
13
//The Initial Developers of the Original Code are Frederik Dietz and Timo
14
// Stich.
15
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
16
//
17
//All Rights Reserved.
18

19 package org.columba.mail.folder.imap;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Arrays JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30
31 import org.columba.api.command.IStatusObservable;
32 import org.columba.core.base.ListTools;
33 import org.columba.core.command.CommandCancelledException;
34 import org.columba.core.command.CommandProcessor;
35 import org.columba.core.connectionstate.ConnectionStateImpl;
36 import org.columba.core.xml.XmlElement;
37 import org.columba.mail.command.MailFolderCommandReference;
38 import org.columba.mail.config.FolderItem;
39 import org.columba.mail.config.IFolderItem;
40 import org.columba.mail.config.ImapItem;
41 import org.columba.mail.folder.AbstractRemoteFolder;
42 import org.columba.mail.folder.IHeaderListCorruptedListener;
43 import org.columba.mail.folder.IMailFolder;
44 import org.columba.mail.folder.IMailbox;
45 import org.columba.mail.folder.RootFolder;
46 import org.columba.mail.folder.command.ApplyFilterCommand;
47 import org.columba.mail.folder.headercache.BerkeleyDBHeaderList;
48 import org.columba.mail.folder.headercache.CachedHeaderfields;
49 import org.columba.mail.folder.search.DefaultSearchEngine;
50 import org.columba.mail.folder.search.IMAPQueryEngine;
51 import org.columba.mail.imap.IImapServer;
52 import org.columba.mail.message.ColumbaHeader;
53 import org.columba.mail.message.ICloseableIterator;
54 import org.columba.mail.message.IColumbaHeader;
55 import org.columba.mail.message.IHeaderList;
56 import org.columba.mail.message.IPersistantHeaderList;
57 import org.columba.mail.parser.PassiveHeaderParserInputStream;
58 import org.columba.mail.util.MailResourceLoader;
59 import org.columba.ristretto.imap.IMAPException;
60 import org.columba.ristretto.imap.IMAPFlags;
61 import org.columba.ristretto.imap.MailboxStatus;
62 import org.columba.ristretto.imap.SearchKey;
63 import org.columba.ristretto.imap.SequenceEntry;
64 import org.columba.ristretto.imap.SequenceSet;
65 import org.columba.ristretto.message.Attributes;
66 import org.columba.ristretto.message.Flags;
67 import org.columba.ristretto.message.Header;
68 import org.columba.ristretto.message.MimeTree;
69
70 public class IMAPFolder extends AbstractRemoteFolder {
71
72     /** JDK 1.4+ logging framework logger, used for logging. */
73     private static final Logger JavaDoc LOG = Logger
74             .getLogger("org.columba.mail.folder.imap");
75
76     /**
77      *
78      */

79     private IImapServer store;
80
81     private IStatusObservable observable;
82
83     /**
84      *
85      */

86     protected boolean existsOnServer = true;
87
88     private boolean readOnly;
89
90     private IPersistantHeaderList headerList;
91
92     private boolean firstSync = true;
93
94     private boolean mailboxSyncEnabled = true;
95
96     /**
97      * @see org.columba.mail.folder.IMailbox#isReadOnly()
98      */

99     public boolean isReadOnly() {
100         return readOnly;
101     }
102
103     /**
104      * Constructor for testing purposes only!
105      *
106      */

107     public IMAPFolder(IPersistantHeaderList headerList, IImapServer server) {
108         super("test", "IMAPFolder", "/tmp/");
109         this.headerList = headerList;
110         this.observable = new DummyObservable();
111
112         store = server;
113     }
114
115     /**
116      * @see org.columba.mail.folder.FolderTreeNode#FolderTreeNode(org.columba.mail.config.FolderItem)
117      */

118     public IMAPFolder(FolderItem folderItem, String JavaDoc path) {
119         super(folderItem, path);
120
121         DefaultSearchEngine engine = new DefaultSearchEngine(this);
122         engine.setNonDefaultEngine(new IMAPQueryEngine(this));
123         setSearchEngine(engine);
124
125     }
126
127     /**
128      * @param type
129      */

130     // only called by FolderFactory
131
public IMAPFolder(String JavaDoc name, String JavaDoc type, String JavaDoc path) throws Exception JavaDoc {
132         super(name, type, path);
133
134         IFolderItem item = getConfiguration();
135         item.setString("property", "accessrights", "user");
136         item.setString("property", "subfolder", "true");
137     }
138
139     /**
140      * @see org.columba.mail.folder.FolderTreeNode#removeFolder()
141      */

142     public void removeFolder() throws Exception JavaDoc {
143         try {
144             if (existsOnServer) {
145                 String JavaDoc path = getImapPath();
146
147                 getServer().deleteFolder(path);
148             }
149
150             super.removeFolder();
151         } catch (Exception JavaDoc e) {
152             throw e;
153         }
154     }
155
156     public void setName(String JavaDoc name) throws Exception JavaDoc {
157         if (getName() == null) { // if creating new folder
158
super.setName(name);
159             return;
160         }
161
162         String JavaDoc oldPath = getImapPath();
163         LOG.info("old path=" + oldPath);
164
165         String JavaDoc newPath = null;
166
167         if (getParent() instanceof IMAPFolder) {
168             newPath = ((IMAPFolder) getParent()).getImapPath();
169         }
170
171         newPath += (getServer().getDelimiter() + name);
172         LOG.info("new path=" + newPath);
173
174         getServer().renameFolder(oldPath, newPath);
175         super.setName(name);
176     }
177
178     /**
179      * Method getStore.
180      *
181      * @return IMAPStore
182      */

183     public IImapServer getServer() {
184         if (store == null) {
185             store = ((IMAPRootFolder) getRootFolder()).getServer();
186         }
187
188         return store;
189     }
190
191     /**
192      * @see org.columba.mail.folder.Folder#getHeaderList(org.columba.api.command.IWorkerStatusController)
193      */

194     public synchronized IHeaderList getHeaderList() throws Exception JavaDoc {
195         if (headerList == null) {
196             // header cache is stored in "headerlist" subfolder
197
File JavaDoc headercacheDirectory = new File JavaDoc(getDirectoryFile(),
198                     "headerlist");
199             headerList = new BerkeleyDBHeaderList(headercacheDirectory, getId());
200
201             headerList
202                     .addHeaderListCorruptedListener(new IHeaderListCorruptedListener() {
203
204                         public void headerListCorrupted(IHeaderList headerList) {
205                             headerList.clear();
206                             getMessageFolderInfo().reset();
207                             fireFolderPropertyChanged();
208                         }
209                     });
210
211         }
212
213         if (mailboxSyncEnabled && ConnectionStateImpl.getInstance().isOnline()
214                 && !getServer().isSelected(this)) {
215             // Trigger Synchronization
216
CommandProcessor.getInstance().addOp(
217                     new CheckForNewMessagesCommand(
218                             new MailFolderCommandReference(this)));
219         }
220
221         return headerList;
222     }
223
224     protected ImapItem getImapItem() {
225         return getServer().getItem();
226     }
227
228     protected void printStatusMessage(String JavaDoc message) {
229         if (getObservable() != null) {
230             getObservable().setMessage(
231                     getImapItem().get("host") + ": " + message);
232         }
233     }
234
235     protected void setProgress(int progress) {
236         if (getObservable() != null) {
237             getObservable().setCurrent(progress);
238         }
239     }
240
241     protected void setMaximum(int progress) {
242         if (getObservable() != null) {
243             getObservable().setMax(progress);
244         }
245     }
246
247     /**
248      * @throws Exception
249      * @throws IOException
250      * @throws CommandCancelledException
251      * @throws IMAPException
252      */

253     Object JavaDoc[] synchronizeHeaderlist() throws Exception JavaDoc, IOException JavaDoc,
254             CommandCancelledException, IMAPException {
255
256         Object JavaDoc[] result = new Object JavaDoc[0];
257
258         // Check if the mailbox has changed
259
MailboxStatus status = getServer().getStatus(this);
260
261         if (status.getMessages() == 0) {
262             purgeHeaderList();
263
264             syncMailboxInfo(status);
265
266             return result;
267         }
268
269         if (!firstSync
270                 && status.getMessages() == this.getMessageFolderInfo()
271                         .getExists()) {
272             return result;
273         }
274
275         List JavaDoc localUids = new LinkedList JavaDoc(Arrays
276                 .asList(getHeaderList().getUids()));
277         // Sort the uid list
278
Collections.sort(localUids);
279
280         int largestLocalUid = localUids.size() > 0 ? ((Integer JavaDoc) localUids
281                 .get(localUids.size() - 1)).intValue() : -1;
282
283         int largestRemoteUid = getServer().getLargestRemoteUid(this);
284
285         if (localUids.size() == status.getMessages()
286                 && largestRemoteUid == largestLocalUid) {
287             // Seems to be no change!
288
if (firstSync) {
289                 firstSync = false;
290                 synchronizeFlags(status);
291             } else {
292                 syncMailboxInfo(status);
293             }
294
295             return result;
296         }
297
298         printStatusMessage(MailResourceLoader.getString("statusbar", "message",
299                 "sync_messages"));
300
301         largestRemoteUid = getServer().fetchUid(
302                 new SequenceSet(SequenceEntry.STAR), this);
303
304         if (largestRemoteUid == -1) {
305             largestRemoteUid = getServer().fetchUid(
306                     new SequenceSet(status.getMessages()), this);
307         }
308
309         int largestLocalUidIndex = findLargestLocalUidIndex(localUids);
310
311         int newMessages = status.getMessages() - largestLocalUidIndex;
312
313         /*
314          * // Somehow there are new messages that // have a lower index -> out
315          * of sync if (localUids.size() - status.getMessages() + newMessages <
316          * 0) {
317          *
318          * LOG.severe("Folder " + getName() + " is out of sync -> recreating the
319          * cache!"); purgeHeaderList(); // all messages are new newMessages =
320          * status.getMessages(); // Set the index of the largest Uid to 0 // ->
321          * ensure it works with the fetch of new // messages part below
322          * largestLocalUidIndex = 0; largestLocalUid = -1;
323          *
324          * localUids.clear(); }
325          */

326         LOG.fine("Found " + newMessages + " new Messages");
327
328         // If we have new messages add them to the headerlist
329
if (newMessages > 0) {
330             printStatusMessage(MailResourceLoader.getString("statusbar",
331                     "message", "fetch_new_headers"));
332
333             // Ensure sizes are correct
334
getMessageFolderInfo().setExists(localUids.size());
335             getMessageFolderInfo().setUnseen(
336                     Math.min(getMessageFolderInfo().getUnseen(), localUids
337                             .size()));
338             getMessageFolderInfo().setRecent(0);
339
340             List JavaDoc newUids = fetchNewMessages(largestLocalUidIndex);
341
342             localUids.addAll(newUids);
343
344             if (newUids.size() < newMessages) {
345                 // There are still more messages to update
346
// -> issue another fetch messages command
347
CommandProcessor.getInstance().addOp(
348                         new FetchMessagesCommand(
349                                 new MailFolderCommandReference(this),
350                                 newMessages, largestLocalUidIndex, newUids
351                                         .size()));
352
353             } else {
354                 fetchDone();
355             }
356
357             result = newUids.toArray(new Object JavaDoc[0]);
358         } else {
359
360             // Number of deleted messages is computed from exists on imap and
361
// local
362
// newMessages
363
findRemovedMessages(status, localUids);
364
365             if (firstSync) {
366                 firstSync = false;
367                 synchronizeFlags(status);
368             } else {
369                 syncMailboxInfo(status);
370             }
371         }
372
373         return result;
374     }
375
376     private int findLargestLocalUidIndex(List JavaDoc localUids) throws IOException JavaDoc,
377             IMAPException, CommandCancelledException {
378         int largestLocalUidIndex = -1;
379
380         printStatusMessage(MailResourceLoader.getString("statusbar", "message",
381                 "sync_messages"));
382
383         // Compute the number of new messages
384
if (localUids.size() > 0) {
385             // Find the index of the largest local Uid
386
int position = localUids.size() - 1;
387             while (largestLocalUidIndex == -1
388                     && position >= localUids.size() - 10 && position >= 0) {
389                 largestLocalUidIndex = getServer().getIndex(
390                         (Integer JavaDoc) localUids.get(position--), this);
391             }
392
393             // Still not found -> do a binary search
394
if (largestLocalUidIndex == -1) {
395                 int a, b, c;
396                 int index;
397                 a = 0;
398                 b = position;
399                 while (b > a && b - a > 1) {
400                     c = Math.round((b - a) * 0.5f) + a;
401
402                     index = getServer().getIndex((Integer JavaDoc) localUids.get(c),
403                             this);
404                     if (index == -1) {
405                         b = c;
406                     } else {
407                         a = c;
408                         largestLocalUidIndex = index;
409                     }
410                 }
411
412                 // removedLocalUids = localUids.size() - 1 - position;
413
} else {
414                 // -2 because of the decrement in line 317
415
// removedLocalUids = localUids.size() - 2 - position;
416
}
417
418             // Check if all local uids have been deleted
419
if (largestLocalUidIndex == -1) {
420                 // all messages are new
421
largestLocalUidIndex = 0;
422             }
423
424         } else {
425             // all messages are new
426
largestLocalUidIndex = 0;
427         }
428         return largestLocalUidIndex;
429     }
430
431     private void findRemovedMessages(MailboxStatus status, List JavaDoc localUids)
432             throws Exception JavaDoc, IOException JavaDoc, IMAPException,
433             CommandCancelledException {
434         int largestRemoteUid = getServer().getLargestRemoteUid(this);
435
436         int deletedMessages = localUids.size() - status.getMessages();
437
438         LOG.fine("Found " + deletedMessages + " deleted Messages");
439
440         // Find the messages that have been deleted
441
if (deletedMessages > 0) {
442             int found = 0;
443             // First deleted all local uids that
444
// are larger than the largest remote uid
445
while (localUids.size() > 0
446                     && found != deletedMessages
447                     && ((Integer JavaDoc) localUids.get(localUids.size() - 1))
448                             .intValue() > largestRemoteUid) {
449                 Flags flags = getHeaderList().remove(
450                         localUids.get(localUids.size() - 1)).getFlags();
451                 fireMessageRemoved(localUids.remove(localUids.size() - 1),
452                         flags);
453
454                 found++;
455             }
456
457             // Search in packs beginning from newest to oldest
458
// -> in most cases this should save us a lot of uid fetchings to
459
// find the deleted messages
460

461             // Pack size is min 10, max 200 else mailboxsize / 10
462
int packSize = Math.min(Math.max(deletedMessages, status
463                     .getMessages() / 10), 200);
464
465             int upper = status.getMessages();
466
467             int localPointer = localUids.size() - 1;
468
469             // Fetch Pack outer loop
470
while (upper >= 1 && found != deletedMessages) {
471                 SequenceSet set = new SequenceSet();
472                 set.add(Math.max(upper - packSize + 1, 1), upper);
473
474                 // Fetch these uids and compare them to the
475
// local list
476
Integer JavaDoc[] actUids = getServer().fetchUids(set, this);
477
478                 // Compare inner loop
479
for (int i = actUids.length - 1; i >= 0
480                         && found != deletedMessages; i--) {
481
482                     // Find missing uids loop
483
while (found != deletedMessages && localPointer >= 0
484                             && !localUids.get(localPointer).equals(actUids[i])) {
485                         // We found the uid of a deleted message
486
// -> remove it from the headerlist
487
getHeaderList().remove(localUids.get(localPointer));
488
489                         found++;
490                         localPointer--;
491                     }
492
493                     // next position in the local uid list
494
localPointer--;
495                 }
496
497                 upper = upper - packSize;
498             }
499
500             // All the other local mails are deleted
501
while (found < deletedMessages && localPointer >= 0) {
502                 getHeaderList().remove(localUids.get(localPointer--));
503                 found++;
504             }
505
506             if (found != deletedMessages) {
507                 LOG.severe("Assertion failed : found only " + found + " of "
508                         + deletedMessages);
509             }
510
511         }
512     }
513
514     private void purgeHeaderList() throws Exception JavaDoc {
515         ICloseableIterator it = getHeaderList().keyIterator();
516         while (it.hasNext()) {
517             Object JavaDoc uid = it.next();
518             fireMessageRemoved(uid, getHeaderList().get(uid).getFlags());
519         }
520         it.close();
521         getHeaderList().clear();
522
523         getMessageFolderInfo().reset();
524         fireFolderPropertyChanged();
525     }
526
527     List JavaDoc fetchNewMessages(int startIndex) throws IOException JavaDoc, IMAPException,
528             CommandCancelledException, Exception JavaDoc {
529         IMAPFlags[] newFlags = getServer().fetchFlagsListStartFrom2(
530                 startIndex + 1, this);
531
532         List JavaDoc newUids = new ArrayList JavaDoc(newFlags.length);
533
534         // Build a list of the new uids
535
for (int i = 0; i < newFlags.length; i++) {
536             // Update the list of new and local uids
537
newUids.add(newFlags[i].getUid());
538         }
539
540         // Fetch the headers of the new messages ...
541
getServer().fetchHeaderList(getHeaderList(), newUids, this);
542
543         // .. and set the flags
544
setFlags(newFlags);
545
546         // fire message added updates
547
for (int i = 0; i < newFlags.length; i++) {
548             fireMessageAdded(newFlags[i].getUid(), newFlags[i]);
549         }
550
551         return newUids;
552     }
553
554     private void syncMailboxInfo(MailboxStatus status) {
555         boolean updated = false;
556         if (status.getMessages() != -1
557                 && messageFolderInfo.getExists() != status.getMessages()) {
558             messageFolderInfo.setExists(status.getMessages());
559             updated = true;
560         }
561
562         if (status.getMessages() == 0) {
563             messageFolderInfo.setRecent(0);
564             messageFolderInfo.setUnseen(0);
565             updated = true;
566         } else {
567
568             if (status.getUnseen() != -1
569                     && messageFolderInfo.getUnseen() != status.getUnseen()) {
570                 messageFolderInfo.setUnseen(status.getUnseen());
571                 updated = true;
572             }
573         }
574
575         // Sanity tests
576
if (messageFolderInfo.getRecent() < 0) {
577             messageFolderInfo.setRecent(0);
578             updated = true;
579         }
580         if (messageFolderInfo.getRecent() > messageFolderInfo.getExists()) {
581             messageFolderInfo.setRecent(messageFolderInfo.getExists());
582             updated = true;
583         }
584
585         if (messageFolderInfo.getUnseen() < 0) {
586             messageFolderInfo.setUnseen(0);
587             updated = true;
588         }
589         if (messageFolderInfo.getUnseen() > messageFolderInfo.getExists()) {
590             messageFolderInfo.setUnseen(messageFolderInfo.getExists());
591             updated = true;
592         }
593
594         if (updated) {
595             fireFolderPropertyChanged();
596         }
597
598     }
599
600     private void synchronizeFlags(MailboxStatus status) throws Exception JavaDoc,
601             IOException JavaDoc, CommandCancelledException, IMAPException {
602         printStatusMessage(MailResourceLoader.getString("statusbar", "message",
603                 "sync_flags"));
604
605         MailboxStatus flagStatus = new MailboxStatus();
606         flagStatus.setMessages(status.getMessages());
607
608         // Build the remote lists of messages that are UNSEEN, FLAGGED, DELETED,
609
// JUNK
610
SearchKey unseenKey = new SearchKey(SearchKey.UNSEEN);
611         List JavaDoc remoteUnseenUids = Arrays.asList(getServer().search(unseenKey,
612                 this));
613         flagStatus.setUnseen(remoteUnseenUids.size());
614
615         SearchKey flaggedKey = new SearchKey(SearchKey.FLAGGED);
616         List JavaDoc remoteFlaggedUids = Arrays.asList(getServer().search(flaggedKey,
617                 this));
618
619         SearchKey deletedKey = new SearchKey(SearchKey.DELETED);
620         List JavaDoc remoteDeletedUids = Arrays.asList(getServer().search(deletedKey,
621                 this));
622
623         SearchKey recentKey = new SearchKey(SearchKey.RECENT);
624         List JavaDoc remoteRecentUids = Arrays.asList(getServer().search(recentKey,
625                 this));
626         flagStatus.setRecent(remoteRecentUids.size());
627
628         SearchKey junkKey = new SearchKey(SearchKey.KEYWORD, "JUNK");
629         List JavaDoc remoteJunkUids = Arrays.asList(getServer().search(junkKey, this));
630
631         // update the local flags and ensure that the MailboxInfo is correct
632
ICloseableIterator headerIterator = getHeaderList().headerIterator();
633
634         int unseen = 0;
635         int flagged = 0;
636         int recent = 0;
637         int deleted = 0;
638         int junk = 0;
639
640         while (headerIterator.hasNext()) {
641             IColumbaHeader header = (IColumbaHeader) headerIterator.next();
642             Object JavaDoc uid = header.get("columba.uid");
643
644             Flags flag = header.getFlags();
645             Flags oldFlag = (Flags) flag.clone();
646
647             int index;
648
649             index = Collections.binarySearch(remoteUnseenUids, uid);
650             flag.setSeen(index < 0);
651             if (!flag.getSeen()) {
652                 unseen++;
653             }
654
655             index = Collections.binarySearch(remoteDeletedUids, uid);
656             flag.setDeleted(index >= 0);
657             if (flag.getDeleted()) {
658                 deleted++;
659             }
660
661             index = Collections.binarySearch(remoteFlaggedUids, uid);
662             flag.setFlagged(index >= 0);
663             if (flag.getFlagged()) {
664                 flagged++;
665             }
666
667             index = Collections.binarySearch(remoteRecentUids, uid);
668             flag.setRecent(index >= 0);
669             if (flag.getRecent()) {
670                 recent++;
671             }
672
673             index = Collections.binarySearch(remoteJunkUids, uid);
674             header.getAttributes().put("columba.spam", new Boolean JavaDoc(index >= 0));
675             if (index >= 0) {
676                 junk++;
677             }
678
679             if (!flag.equals(oldFlag)) {
680                 getHeaderList().update(uid, header);
681
682                 fireMessageFlagChanged(uid, oldFlag, 0);
683             }
684         }
685         headerIterator.close();
686
687         if (remoteJunkUids.size() != junk || remoteRecentUids.size() != recent
688                 || remoteFlaggedUids.size() != flagged
689                 || remoteDeletedUids.size() != deleted
690                 || remoteUnseenUids.size() != unseen) {
691             // Something is wrong
692
// Sync again
693

694             synchronizeHeaderlist();
695             return;
696         }
697
698         syncMailboxInfo(flagStatus);
699     }
700
701     /**
702      * Method updateFlags.
703      *
704      * @param flagsList
705      */

706     protected void setFlags(Flags[] flagsList) throws Exception JavaDoc {
707         for (int i = 0; i < flagsList.length; i++) {
708             IMAPFlags flags = (IMAPFlags) flagsList[i];
709
710             Integer JavaDoc uid = (Integer JavaDoc) flags.getUid();
711
712             IColumbaHeader header = getHeaderList().get(uid);
713
714             Flags localFlags = header.getFlags();
715
716             localFlags.setFlags(flags.getFlags());
717
718             // Junk flag
719
header.getAttributes().put("columba.spam",
720                     Boolean.valueOf(flags.get(IMAPFlags.JUNK)));
721
722             getHeaderList().update(uid, header);
723         }
724     }
725
726     /**
727      * @see org.columba.mail.folder.Folder#getMimeTree(java.lang.Object,
728      * IMAPFolder)
729      */

730     public MimeTree getMimePartTree(Object JavaDoc uid) throws Exception JavaDoc {
731         MimeTree tree = IMAPCache.getInstance().getMimeTree(this, uid);
732         if (tree == null) {
733             tree = getServer().getMimeTree(uid, this);
734             IMAPCache.getInstance().addMimeTree(this, uid, tree);
735         }
736
737         return tree;
738     }
739
740     /**
741      * Copies a set of messages from this folder to a destination folder.
742      * <p>
743      * The IMAP copy command also keeps the flags intact. So, there's no need to
744      * change these manually.
745      *
746      * @see org.columba.mail.folder.Folder#innerCopy(org.columba.mail.folder.IMailbox,
747      * java.lang.Object, org.columba.api.command.IWorkerStatusController)
748      */

749     public void innerCopy(IMailbox destiny, Object JavaDoc[] uids) throws Exception JavaDoc {
750         IMAPFolder destFolder = (IMAPFolder) destiny;
751         IHeaderList srcHeaderList = getHeaderList();
752         IPersistantHeaderList destHeaderList = (IPersistantHeaderList) destFolder
753                 .getHeaderList();
754
755         Object JavaDoc[] destUids = getServer().copy(destFolder, uids, this);
756
757         if (destUids.length < uids.length) {
758             LOG
759                     .warning("Some messages could not be copied because they do not exist anymore!");
760         }
761
762         // Check if maybe no message at all got copied
763
// In this case we are finished here
764
if (destUids.length == 0)
765             return;
766
767         // update headerlist of destination-folder
768
// -> this is necessary to reflect the changes visually
769
// but only do it if the target folder is still in sync!
770

771         Integer JavaDoc largestDestUid = new Integer JavaDoc(-1);
772         ICloseableIterator it = destHeaderList.keyIterator();
773         while (it.hasNext()) {
774             Integer JavaDoc uid = (Integer JavaDoc) it.next();
775             if (largestDestUid.compareTo(uid) < 0) {
776                 largestDestUid = uid;
777             }
778         }
779         it.close();
780
781         if (((Integer JavaDoc) destUids[0]).intValue() == largestDestUid.intValue() + 1) {
782             int j = 0;
783             for (int i = 0; i < uids.length; i++) {
784                 IColumbaHeader destHeader = srcHeaderList.get(uids[i]);
785                 // Was this message actually copied?
786
if (destHeader != null) {
787                     // Copy the header
788
destHeader = (IColumbaHeader) destHeader.clone();
789
790                     destHeader.set("columba.uid", destUids[j]);
791                     destHeaderList.add(destHeader, destUids[j]);
792
793                     // We need IMAPFlags
794
IMAPFlags flags = new IMAPFlags(destHeader.getFlags()
795                             .getFlags());
796                     flags.setUid(destUids[j]);
797
798                     destFolder.fireMessageAdded(flags.getUid(), flags);
799                     j++;
800                 }
801             }
802         }
803
804     }
805
806     /**
807      * @see org.columba.mail.folder.Folder#markMessage(java.lang.Object, int,
808      * IMAPFolder)
809      */

810     public void markMessage(Object JavaDoc[] uids, int variant) throws Exception JavaDoc {
811         getServer().markMessage(uids, variant, this);
812
813         super.markMessage(uids, variant);
814     }
815
816     /**
817      * @see org.columba.mail.folder.Folder#expungeFolder(java.lang.Object,
818      * org.columba.api.command.IWorkerStatusController)
819      */

820     public void expungeFolder() throws Exception JavaDoc {
821         try {
822             getServer().expunge(this);
823             super.expungeFolder();
824         } catch (Exception JavaDoc e) {
825             throw e;
826         }
827     }
828
829     /**
830      * @see org.columba.mail.folder.Folder#getMessageHeader(java.lang.Object,
831      * org.columba.api.command.IWorkerStatusController)
832      * @TODO dont use deprecated method
833      */

834     public IColumbaHeader getMessageHeader(Object JavaDoc uid) throws Exception JavaDoc {
835         return getHeaderList().get(uid);
836     }
837
838     /**
839      * Method getImapPath.
840      *
841      * @return String
842      */

843     public String JavaDoc getImapPath() throws IOException JavaDoc, IMAPException,
844             CommandCancelledException {
845         StringBuffer JavaDoc path = new StringBuffer JavaDoc();
846         path.append(getName());
847
848         IMailFolder child = this;
849
850         while (true) {
851             child = (IMailFolder) child.getParent();
852
853             if (child instanceof IMAPRootFolder) {
854                 break;
855             }
856
857             String JavaDoc n = ((IMAPFolder) child).getName();
858
859             path.insert(0, n + getServer().getDelimiter());
860         }
861
862         return path.toString();
863     }
864
865     /**
866      * @see org.columba.mail.folder.FolderTreeNode#getDefaultProperties()
867      */

868     public static XmlElement getDefaultProperties() {
869         XmlElement props = new XmlElement("property");
870
871         props.addAttribute("accessrights", "user");
872         props.addAttribute("subfolder", "true");
873
874         return props;
875     }
876
877     /**
878      * @see org.columba.mail.folder.FolderTreeNode#tryToGetLock(java.lang.Object)
879      */

880     public boolean tryToGetLock(Object JavaDoc locker) {
881         // IMAP Folders have no own lock ,but share the lock from the Root
882
// to ensure that only one operation can be processed simultanous
883
IMailFolder root = getRootFolder();
884         if (root == null)
885             throw new IllegalArgumentException JavaDoc("IMAPRoot is null");
886
887         return root.tryToGetLock(locker);
888     }
889
890     /**
891      * @see org.columba.mail.folder.FolderTreeNode#releaseLock()
892      */

893     public void releaseLock(Object JavaDoc locker) {
894         IMailFolder root = getRootFolder();
895         if (root == null)
896             throw new IllegalArgumentException JavaDoc("IMAPRoot is null");
897
898         root.releaseLock(locker);
899     }
900
901     /*
902      * (non-Javadoc)
903      *
904      * @see org.columba.mail.folder.FolderTreeNode#addSubfolder(org.columba.mail.folder.FolderTreeNode)
905      */

906     public void addSubfolder(IMailFolder child) throws Exception JavaDoc {
907         if (child instanceof IMAPFolder) {
908
909             getServer().createMailbox(child.getName(), this);
910         }
911
912         super.addSubfolder(child);
913     }
914
915     /*
916      * (non-Javadoc)
917      *
918      * @see org.columba.mail.folder.Folder#getObservable()
919      */

920     public IStatusObservable getObservable() {
921         if (observable == null) {
922             observable = ((IMAPRootFolder) getRootFolder()).getObservable();
923         }
924
925         return observable;
926     }
927
928     /*
929      * (non-Javadoc)
930      *
931      * @see org.columba.mail.folder.IMailbox#addMessage(java.io.InputStream)
932      */

933     public Object JavaDoc addMessage(InputStream JavaDoc in, Attributes attributes, Flags flags)
934             throws Exception JavaDoc {
935         PassiveHeaderParserInputStream withHeaderInputStream = new PassiveHeaderParserInputStream(
936                 in);
937
938         IMAPFlags imapFlags = new IMAPFlags(flags.getFlags());
939
940         Integer JavaDoc uid = getServer()
941                 .append(withHeaderInputStream, imapFlags, this);
942
943         // Since JUNK is a non-system Flag we have to set it with
944
// an addtitional STORE command
945
if (((Boolean JavaDoc) attributes.get("columba.spam")).booleanValue()) {
946             imapFlags.set(IMAPFlags.JUNK, true);
947
948             getServer().setFlags(new Object JavaDoc[] { uid }, imapFlags, this);
949         }
950
951         // Parser the header
952
Header header = withHeaderInputStream.getHeader();
953
954         // update the HeaderList
955
IColumbaHeader cHeader = new ColumbaHeader(header,
956                 (Attributes) attributes.clone(), imapFlags);
957
958         getHeaderList().add(cHeader, uid);
959
960         fireMessageAdded(uid, cHeader.getFlags());
961
962         return uid;
963     }
964
965     /*
966      * (non-Javadoc)
967      *
968      * @see org.columba.mail.folder.IMailbox#getHeaderFields(java.lang.Object,
969      * java.lang.String[])
970      */

971     public Header getHeaderFields(Object JavaDoc uid, String JavaDoc[] keys) throws Exception JavaDoc {
972         // get header with UID
973
IColumbaHeader header = getHeaderList().get(uid);
974
975         if (header == null)
976             return new Header();
977
978         // cached headerfield list
979
List JavaDoc cachedList = Arrays.asList(CachedHeaderfields
980                 .getDefaultHeaderfields());
981
982         List JavaDoc keyList = new ArrayList JavaDoc(Arrays.asList(keys));
983         ListTools.substract(keyList, cachedList);
984
985         if (keyList.size() > 0) {
986             return getServer().getHeaders(uid, keys, this);
987         } else {
988             return (Header) header.getHeader().clone();
989         }
990     }
991
992     /*
993      * (non-Javadoc)
994      *
995      * @see org.columba.mail.folder.IMailbox#getMessageSourceStream(java.lang.Object)
996      */

997     public InputStream JavaDoc getMessageSourceStream(Object JavaDoc uid) throws Exception JavaDoc {
998         return getServer().getMessageSourceStream(uid, this);
999     }
1000
1001    /*
1002     * (non-Javadoc)
1003     *
1004     * @see org.columba.mail.folder.IMailbox#getMimePartSourceStream(java.lang.Object,
1005     * java.lang.Integer[])
1006     */

1007    public InputStream JavaDoc getMimePartSourceStream(Object JavaDoc uid, Integer JavaDoc[] address)
1008            throws Exception JavaDoc {
1009        return getServer().getMimePartSourceStream(uid, address, this);
1010    }
1011
1012    /**
1013     *
1014     *
1015     * @see org.columba.mail.folder.IMailbox#getMimePartBodyStream(java.lang.Object,
1016     * java.lang.Integer[])
1017     */

1018    public InputStream JavaDoc getMimePartBodyStream(Object JavaDoc uid, Integer JavaDoc[] address)
1019            throws Exception JavaDoc {
1020        InputStream JavaDoc result = IMAPCache.getInstance().getMimeBody(this, uid,
1021                address);
1022        if (result == null) {
1023            LOG.fine("Cache miss - fetching from server");
1024            result = IMAPCache.getInstance().addMimeBody(this, uid, address,
1025                    getServer().getMimePartBodyStream(uid, address, this));
1026        }
1027        return result;
1028    }
1029
1030    /*
1031     * (non-Javadoc)
1032     *
1033     * @see org.columba.mail.folder.Folder#isInboxFolder()
1034     */

1035    public boolean isInboxFolder() {
1036        RootFolder root = (RootFolder) getRootFolder();
1037
1038        if (root != null) {
1039            return root.getInboxFolder() == this;
1040        } else {
1041            return false;
1042        }
1043    }
1044
1045    /*
1046     * (non-Javadoc)
1047     *
1048     * @see org.columba.mail.folder.Folder#isTrashFolder()
1049     */

1050    public boolean isTrashFolder() {
1051        RootFolder root = (RootFolder) getRootFolder();
1052
1053        if (root != null) {
1054            return root.getTrashFolder() == this;
1055        } else {
1056            return false;
1057        }
1058    }
1059
1060    /*
1061     * (non-Javadoc)
1062     *
1063     * @see org.columba.mail.folder.IMailbox#addMessage(java.io.InputStream,
1064     * org.columba.ristretto.message.Attributes)
1065     */

1066    public Object JavaDoc addMessage(InputStream JavaDoc in) throws Exception JavaDoc {
1067        PassiveHeaderParserInputStream withHeaderInputStream = new PassiveHeaderParserInputStream(
1068                in);
1069
1070        Integer JavaDoc uid = getServer().append(withHeaderInputStream, this);
1071
1072        if (getServer().isSelected(this)) {
1073            // update the HeaderList
1074
Header header = withHeaderInputStream.getHeader();
1075            ColumbaHeader h = new ColumbaHeader(header);
1076            getHeaderList().add(h, uid);
1077
1078            fireMessageAdded(uid, h.getFlags());
1079        } else {
1080            if (mailboxSyncEnabled) {
1081                // Trigger Synchronization
1082
CommandProcessor.getInstance().addOp(
1083                        new CheckForNewMessagesCommand(
1084                                new MailFolderCommandReference(this)));
1085            }
1086        }
1087
1088        return uid;
1089    }
1090
1091    /**
1092     * @see org.columba.mail.folder.Folder#getHeaderListStorage()
1093     */

1094    /*
1095     * public IHeaderListStorage getHeaderListStorage() { if (attributeStorage ==
1096     * null) attributeStorage = new RemoteHeaderListStorage(this);
1097     *
1098     * return attributeStorage; }
1099     */

1100
1101    /**
1102     * @see org.columba.mail.folder.Folder#getSearchEngineInstance()
1103     */

1104    public DefaultSearchEngine getSearchEngine() {
1105        if (searchEngine == null) {
1106            searchEngine = new DefaultSearchEngine(this);
1107            searchEngine.setNonDefaultEngine(new IMAPQueryEngine(this));
1108        }
1109
1110        return searchEngine;
1111    }
1112
1113    /**
1114     * @see org.columba.mail.folder.IMailbox#getAllHeaderFields(java.lang.Object)
1115     */

1116    public Header getAllHeaderFields(Object JavaDoc uid) throws Exception JavaDoc {
1117        return getServer().getAllHeaders(uid, this);
1118
1119    }
1120
1121    /**
1122     * @see org.columba.mail.folder.AbstractFolder#supportsAddFolder()
1123     */

1124    public boolean supportsAddFolder(String JavaDoc folder) {
1125        return true;
1126    }
1127
1128    /**
1129     * This is called from the UpdateFlagCommand which gets triggered from an
1130     * unexpected flags updated.
1131     *
1132     * @param flag
1133     * @throws IOException
1134     * @throws CommandCancelledException
1135     * @throws IMAPException
1136     */

1137    public void updateFlag(IMAPFlags flag) throws Exception JavaDoc,
1138            CommandCancelledException {
1139        if (getServer().isSelected(this)) {
1140            Integer JavaDoc uid = new Integer JavaDoc(getServer().fetchUid(
1141                    new SequenceSet(flag.getIndex()), this));
1142            flag.setUid(uid);
1143            setFlags(new Flags[] { flag });
1144        }
1145    }
1146
1147    /**
1148     * @param readOnly
1149     * The readOnly to set.
1150     */

1151    public void setReadOnly(boolean readOnly) {
1152        this.readOnly = readOnly;
1153    }
1154
1155    /*
1156     * (non-Javadoc)
1157     *
1158     * @see org.columba.mail.folder.AbstractMessageFolder#save()
1159     */

1160    public void save() throws Exception JavaDoc {
1161        super.save();
1162
1163        if (headerList != null)
1164            headerList.persist();
1165    }
1166
1167    void fetchDone() throws IOException JavaDoc, CommandCancelledException,
1168            IMAPException, Exception JavaDoc {
1169        MailboxStatus status = getServer().getStatus(this);
1170
1171        List JavaDoc localUids = new LinkedList JavaDoc(Arrays
1172                .asList(getHeaderList().getUids()));
1173        // Sort the uid list
1174
Collections.sort(localUids);
1175
1176        // Number of deleted messages is computed from exists on imap and local
1177
// newMessages
1178
findRemovedMessages(status, localUids);
1179
1180        if (firstSync) {
1181            firstSync = false;
1182            synchronizeFlags(status);
1183        } else {
1184            syncMailboxInfo(status);
1185        }
1186
1187        // Apply filter if enabled
1188
ImapItem item = getServer().getItem();
1189
1190        boolean applyFilter = item.getBooleanWithDefault(
1191                "automatically_apply_filter", false);
1192
1193        // if "automatically apply filter" is selected & there
1194
// are
1195
// new
1196
// messages
1197
if (applyFilter) {
1198            CommandProcessor.getInstance()
1199                    .addOp(
1200                            new ApplyFilterCommand(
1201                                    new MailFolderCommandReference(this)));
1202        }
1203
1204        // Reenable Updating the mailbox
1205
mailboxSyncEnabled = true;
1206    }
1207
1208    /**
1209     * @return Returns the mailboxSyncEnabled.
1210     */

1211    public boolean isMailboxSyncEnabled() {
1212        return mailboxSyncEnabled;
1213    }
1214
1215    /**
1216     * @param mailboxSyncEnabled
1217     * The mailboxSyncEnabled to set.
1218     */

1219    public void setMailboxSyncEnabled(boolean mailboxSyncEnabled) {
1220        this.mailboxSyncEnabled = mailboxSyncEnabled;
1221    }
1222
1223}
Popular Tags