001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: //(the "License"); you may not use this file except in compliance with the
004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: //Software distributed under the License is distributed on an "AS IS" basis,
007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: //for the specific language governing rights and
009: //limitations under the License.
010: //
011: //The Original Code is "The Columba Project"
012: //
013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: //All Rights Reserved.
018:
019: package org.columba.mail.folder;
020:
021: import java.io.File;
022: import java.io.InputStream;
023: import java.nio.charset.Charset;
024: import java.nio.charset.UnsupportedCharsetException;
025: import java.util.logging.Logger;
026:
027: import org.columba.api.command.IStatusObservable;
028: import org.columba.core.command.StatusObservableImpl;
029: import org.columba.core.filter.FilterList;
030: import org.columba.core.filter.IFilter;
031: import org.columba.core.filter.IFilterList;
032: import org.columba.core.io.DiskIO;
033: import org.columba.core.xml.XmlElement;
034: import org.columba.mail.config.FolderItem;
035: import org.columba.mail.config.IFolderItem;
036: import org.columba.mail.folder.command.MarkMessageCommand;
037: import org.columba.mail.folder.event.FolderEvent;
038: import org.columba.mail.folder.event.IFolderListener;
039: import org.columba.mail.folder.search.DefaultSearchEngine;
040: import org.columba.mail.message.ICloseableIterator;
041: import org.columba.mail.message.IColumbaHeader;
042: import org.columba.mail.message.IHeaderList;
043: import org.columba.ristretto.coder.Base64DecoderInputStream;
044: import org.columba.ristretto.coder.CharsetDecoderInputStream;
045: import org.columba.ristretto.coder.QuotedPrintableDecoderInputStream;
046: import org.columba.ristretto.message.Attributes;
047: import org.columba.ristretto.message.Flags;
048: import org.columba.ristretto.message.MailboxInfo;
049: import org.columba.ristretto.message.MimeHeader;
050:
051: /**
052: * Abstract Basic AbstractMessageFolder class. It is subclassed by every folder
053: * class containing messages and therefore offering methods to alter the
054: * mailbox.
055: * <p>
056: * Folders are plugins and therefore dynamically created. This should make it
057: * easy to write new folders in the future.
058: * <p>
059: * To make it very easy to add new local mailbox formats, we added a slightly
060: * more complex class hierachy in org.columba.mail.folder,
061: * org.columba.mail.folder.headercache. An implementation example can be found
062: * in org.columba.mail.folder.mh.
063: * <p>
064: * Please note, that you only need to implement {@link DataStorageInstance}
065: * which should be trivial in most cases. Then create a class extending
066: * {@link AbstractLocalFolder}and plug your datastorage in this folder in
067: * overwriting getDataStorageInstance() method.
068: * <p>
069: * Last, don't forget to register your folder plugin:
070: * <p>
071: * Add your folder to <code>org.columba.mail.plugin.folder.xml</code>. This
072: * way you create an association of the folder name and the class which gets
073: * loaded.
074: * <p>
075: * Edit your tree.xml file and replace the MH mailbox implementation with yours.
076: *
077: * @author freddy
078: * @created 19. Juni 2001
079: */
080: public abstract class AbstractMessageFolder extends AbstractFolder
081: implements IMailbox {
082:
083: /** JDK 1.4+ logging framework logger, used for logging. */
084: private static final Logger LOG = Logger
085: .getLogger("org.columba.mail.folder");
086:
087: /**
088: * total/unread/recent count of messages in this folder
089: */
090: protected IMailboxInfo messageFolderInfo = new ColumbaMailboxInfo();
091:
092: /**
093: * list of filters
094: */
095: protected FilterList filterList;
096:
097: /**
098: *
099: * set changed to true if the folder data changes.
100: */
101: protected boolean changed = false;
102:
103: /**
104: * directory where this folders files are stored
105: */
106: protected File directoryFile;
107:
108: /**
109: * The last selected uid for the current folder. This information is used to
110: * show the last selected message, if you switch to the current folder and
111: * the lastSelection field is set. If the lastSelection field is null, the
112: * first message in the table for this folder is shown. Have a look to
113: * org.columba.mail.gui.table.TableController#showHeaderList
114: */
115: protected Object lastSelection;
116:
117: /**
118: * Status information updates are handled in using IStatusObservable.
119: * <p>
120: * Every command has to register its interest to this events before
121: * accessing the folder.
122: */
123: protected IStatusObservable observable = new StatusObservableImpl();
124:
125: // implement your own search-engine here
126: protected DefaultSearchEngine searchEngine;
127:
128: /**
129: * Standard constructor.
130: *
131: * @param item
132: * <class>FolderItem </class> contains information about the
133: * folder
134: */
135: public AbstractMessageFolder(FolderItem item, String path) {
136: super (item);
137:
138: String dir = path + System.getProperty("file.separator")
139: + getId();
140:
141: if (DiskIO.ensureDirectory(dir)) {
142: directoryFile = new File(dir);
143: }
144:
145: loadMessageFolderInfo();
146: }
147:
148: // used by virtual folder only
149: public AbstractMessageFolder(FolderItem item) {
150: super (item);
151:
152: loadMessageFolderInfo();
153: }
154:
155: protected AbstractMessageFolder() {
156: super ();
157: }
158:
159: /**
160: * @param type
161: */
162: public AbstractMessageFolder(String name, String type, String path) {
163: super (name, type);
164:
165: String dir = path + System.getProperty("file.separator")
166: + getId();
167:
168: if (DiskIO.ensureDirectory(dir)) {
169: directoryFile = new File(dir);
170: }
171:
172: loadMessageFolderInfo();
173: }
174:
175: // only used by VirtualFolder
176: public AbstractMessageFolder(String name, String type) {
177: super (name, type);
178:
179: loadMessageFolderInfo();
180: }
181:
182: protected void recreateMessageFolderInfo() {
183: messageFolderInfo.reset();
184:
185: try {
186: ICloseableIterator it = getHeaderList().headerIterator();
187:
188: while (it.hasNext()) {
189: Flags flags = ((IColumbaHeader) it.next()).getFlags();
190: messageFolderInfo.incExists();
191: if (flags.getRecent()) {
192: messageFolderInfo.incRecent();
193: }
194: if (!flags.getSeen()) {
195: messageFolderInfo.incUnseen();
196: }
197: }
198:
199: } catch (Exception e) {
200: LOG.severe(e.getLocalizedMessage());
201: }
202:
203: }
204:
205: /**
206: * Propagates an event to all registered listeners notifying them of a
207: * message addition.
208: *
209: * @param flags
210: */
211: public void fireMessageAdded(Object uid, Flags flags) {
212: try {
213: getMessageFolderInfo().incExists();
214:
215: if (flags.getRecent()) {
216: getMessageFolderInfo().incRecent();
217: }
218: if (!flags.getSeen()) {
219: getMessageFolderInfo().incUnseen();
220: }
221: } catch (MailboxInfoInvalidException e) {
222: recreateMessageFolderInfo();
223: }
224: setChanged(true);
225:
226: // update treenode
227: fireFolderPropertyChanged();
228:
229: FolderEvent e = new FolderEvent(this , uid);
230: // Guaranteed to return a non-null array
231: Object[] listeners = listenerList.getListenerList();
232:
233: // Process the listeners last to first, notifying
234: // those that are interested in this event
235: for (int i = listeners.length - 2; i >= 0; i -= 2) {
236: if (listeners[i] == IFolderListener.class) {
237: ((IFolderListener) listeners[i + 1]).messageAdded(e);
238: }
239: }
240: }
241:
242: /**
243: * Propagates an event to all registered listeners notifying them of a
244: * message removal.
245: */
246: public void fireMessageRemoved(Object uid, Flags flags) {
247:
248: try {
249: if (flags != null) {
250: if (flags.getRecent()) {
251: getMessageFolderInfo().decRecent();
252: }
253: if (!flags.getSeen()) {
254: getMessageFolderInfo().decUnseen();
255: }
256: }
257: getMessageFolderInfo().decExists();
258: } catch (MailboxInfoInvalidException e) {
259: recreateMessageFolderInfo();
260: }
261:
262: setChanged(true);
263:
264: // update treenode
265: fireFolderPropertyChanged();
266:
267: FolderEvent e = new FolderEvent(this , uid);
268: // Guaranteed to return a non-null array
269: Object[] listeners = listenerList.getListenerList();
270:
271: // Process the listeners last to first, notifying
272: // those that are interested in this event
273: for (int i = listeners.length - 2; i >= 0; i -= 2) {
274: if (listeners[i] == IFolderListener.class) {
275: ((IFolderListener) listeners[i + 1]).messageRemoved(e);
276: }
277: }
278: }
279:
280: /**
281: * Propagates an event to all registered listeners notifying them of a
282: * message removal.
283: */
284: public void fireMessageFlagChanged(Object uid, Flags oldFlags,
285: int variant) {
286:
287: // @author fdietz
288: // -> Moved code for updating mailfolderinfo to markMessage()
289: // intentionally!
290: //
291: setChanged(true);
292:
293: FolderEvent e = new FolderEvent(this , uid, oldFlags, variant);
294:
295: // Guaranteed to return a non-null array
296: Object[] listeners = listenerList.getListenerList();
297:
298: // Process the listeners last to first, notifying
299: // those that are interested in this event
300: for (int i = listeners.length - 2; i >= 0; i -= 2) {
301: if (listeners[i] == IFolderListener.class) {
302: ((IFolderListener) listeners[i + 1])
303: .messageFlagChanged(e);
304: }
305: }
306: }
307:
308: /**
309: * Returns the directory where the messages are saved
310: *
311: * @return File the file representing the mailbox directory
312: */
313: public File getDirectoryFile() {
314: return directoryFile;
315: }
316:
317: /**
318: * Call this method if folder data changed, so that we know if we have to
319: * save the header cache.
320: *
321: * @param b
322: */
323: public void setChanged(boolean b) {
324: changed = b;
325: }
326:
327: /**
328: * Change the <class>MessageFolderInfo </class>
329: *
330: * @param i
331: * the new messagefolderinfo
332: */
333: public void setMessageFolderInfo(MailboxInfo i) {
334: messageFolderInfo = new ColumbaMailboxInfo(i);
335: }
336:
337: /**
338: * Check if folder was modified.
339: *
340: * @return boolean True, if folder data changed. False, otherwise.
341: */
342: protected boolean hasChanged() {
343: return changed;
344: }
345:
346: /**
347: * Method getMessageFolderInfo.
348: *
349: * @return MessageFolderInfo
350: */
351: public IMailboxInfo getMessageFolderInfo() {
352: return messageFolderInfo;
353: }
354:
355: /**
356: * Method getFilterList.
357: *
358: * @return FilterList
359: */
360: public IFilterList getFilterList() {
361: return filterList;
362: }
363:
364: /** ********************************** treenode implementation ********** */
365: /**
366: * @see java.lang.Object#toString()
367: */
368: public String toString() {
369: return getName();
370: }
371:
372: /**
373: * save messagefolderinfo to xml-configuration
374: *
375: */
376: protected void saveMessageFolderInfo() {
377: IMailboxInfo info = getMessageFolderInfo();
378:
379: IFolderItem item = getConfiguration();
380:
381: XmlElement property = item.getElement("property");
382:
383: property.addAttribute("exists", new Integer(info.getExists())
384: .toString());
385: property.addAttribute("unseen", new Integer(info.getUnseen())
386: .toString());
387: // on startup, there's shouldn't be any recent messages
388: // -> we simply remember 0 recent messages here
389: // property.addAttribute("recent", "0");
390:
391: property.addAttribute("recent", new Integer(info.getRecent())
392: .toString());
393:
394: if (info.getUidNext() != -1) {
395: property.addAttribute("uidnext", new Integer(info
396: .getUidNext()).toString());
397: property.addAttribute("uidvalidity", new Integer(info
398: .getUidValidity()).toString());
399: }
400:
401: }
402:
403: /**
404: *
405: * get messagefolderinfo from xml-configuration
406: *
407: */
408: protected void loadMessageFolderInfo() {
409: XmlElement property = getConfiguration().getElement("property");
410:
411: if (property == null) {
412: return;
413: }
414:
415: IMailboxInfo info = getMessageFolderInfo();
416:
417: String exists = property.getAttribute("exists");
418:
419: if (exists != null) {
420: info.setExists(Integer.parseInt(exists));
421: }
422:
423: String recent = property.getAttribute("recent");
424:
425: if (recent != null) {
426: info.setRecent(Integer.parseInt(recent));
427: }
428:
429: String unseen = property.getAttribute("unseen");
430:
431: if (unseen != null) {
432: info.setUnseen(Integer.parseInt(unseen));
433: }
434:
435: String uidnext = property.getAttribute("uidnext");
436:
437: if (uidnext != null) {
438: info.setUidNext(Integer.parseInt(uidnext));
439: }
440:
441: String uidvalidity = property.getAttribute("uidvalidty");
442:
443: if (uidvalidity != null) {
444: info.setUidValidity(Integer.parseInt(uidvalidity));
445: }
446:
447: // Check if the MessageFolderInfo is sane
448: if (!info.isSane()) {
449: recreateMessageFolderInfo();
450: }
451:
452: }
453:
454: /**
455: *
456: * use this method to save folder meta-data when closing Columba
457: *
458: */
459: public void save() throws Exception {
460: saveMessageFolderInfo();
461: if (getSearchEngine() != null) {
462: getSearchEngine().save();
463: }
464: }
465:
466: /**
467: * Returns the last selected Message for the current folder. If no message
468: * was selected, it returns null. The return-value is the uid of the last
469: * selected message.
470: */
471: public Object getLastSelection() {
472: return lastSelection;
473: }
474:
475: /**
476: * Sets the last selection for the current folder. This should be the uid of
477: * the last selected Message for the current folder.
478: */
479: public void setLastSelection(Object lastSel) {
480: lastSelection = lastSel;
481: }
482:
483: /**
484: * @return observable containing status information
485: */
486: public IStatusObservable getObservable() {
487: return observable;
488: }
489:
490: /**
491: * @see org.columba.mail.folder.FolderTreeNode#supportsAddMessage()
492: */
493: public boolean supportsAddMessage() {
494: return true;
495: }
496:
497: /**
498: * Returns true if this folder is an Inbox folder.
499: *
500: * @return true if this folder is an Inbox folder.
501: */
502: public boolean isInboxFolder() {
503: return false;
504: }
505:
506: /**
507: * Returns true if this folder is the Trash folder.
508: *
509: * @return true if this folder is the Trash folder.
510: */
511: public boolean isTrashFolder() {
512: return false;
513: }
514:
515: protected void updateMailFolderInfo(Flags flags, int variant)
516: throws Exception {
517: boolean updated = false;
518:
519: if (flags == null) {
520: return;
521: }
522:
523: try {
524: switch (variant) {
525: case MarkMessageCommand.MARK_AS_READ: {
526: if (flags.getRecent()) {
527: getMessageFolderInfo().decRecent();
528: updated = true;
529: }
530:
531: if (!flags.getSeen()) {
532: getMessageFolderInfo().decUnseen();
533: updated = true;
534: }
535:
536: break;
537: }
538:
539: case MarkMessageCommand.MARK_AS_UNREAD: {
540: if (flags.getSeen()) {
541: getMessageFolderInfo().incUnseen();
542: updated = true;
543: }
544:
545: break;
546: }
547:
548: case MarkMessageCommand.MARK_AS_EXPUNGED: {
549: if (!flags.getSeen()) {
550: getMessageFolderInfo().decUnseen();
551: updated = true;
552: }
553:
554: if (flags.getRecent()) {
555: getMessageFolderInfo().decRecent();
556: updated = true;
557: }
558:
559: break;
560: }
561:
562: case MarkMessageCommand.MARK_AS_RECENT: {
563: if (!flags.getRecent()) {
564: getMessageFolderInfo().incRecent();
565: updated = true;
566: }
567:
568: break;
569: }
570: case MarkMessageCommand.MARK_AS_NOTRECENT: {
571: if (flags.getRecent()) {
572: getMessageFolderInfo().decRecent();
573: updated = true;
574: }
575:
576: break;
577: }
578:
579: }
580: } catch (MailboxInfoInvalidException e) {
581: recreateMessageFolderInfo();
582: }
583:
584: // update treenode
585: if (updated)
586: fireFolderPropertyChanged();
587: }
588:
589: /**
590: * @param uid
591: * @param variant
592: * @param worker
593: * @throws Exception
594: */
595: protected void markMessage(Object uid, int variant)
596: throws Exception {
597: IColumbaHeader header = getHeaderList().get(uid);
598:
599: Flags flags = header.getFlags();
600:
601: updateMailFolderInfo(flags, variant);
602:
603: if (flags == null) {
604: return;
605: }
606: Flags oldFlags = (Flags) flags.clone();
607:
608: switch (variant) {
609: case MarkMessageCommand.MARK_AS_READ: {
610:
611: flags.setSeen(true);
612: flags.setRecent(false);
613:
614: break;
615: }
616:
617: case MarkMessageCommand.MARK_AS_UNREAD: {
618:
619: flags.setSeen(false);
620:
621: break;
622: }
623:
624: case MarkMessageCommand.MARK_AS_FLAGGED: {
625: flags.setFlagged(true);
626:
627: break;
628: }
629:
630: case MarkMessageCommand.MARK_AS_UNFLAGGED: {
631: flags.setFlagged(false);
632:
633: break;
634: }
635:
636: case MarkMessageCommand.MARK_AS_EXPUNGED: {
637:
638: flags.setSeen(true);
639: flags.setRecent(false);
640: flags.setDeleted(true);
641:
642: break;
643: }
644:
645: case MarkMessageCommand.MARK_AS_UNEXPUNGED: {
646: flags.setDeleted(false);
647:
648: break;
649: }
650:
651: case MarkMessageCommand.MARK_AS_ANSWERED: {
652: flags.setAnswered(true);
653:
654: break;
655: }
656: case MarkMessageCommand.MARK_AS_UNANSWERED: {
657: flags.setAnswered(false);
658:
659: break;
660: }
661:
662: case MarkMessageCommand.MARK_AS_SPAM: {
663: header.getAttributes().put("columba.spam", Boolean.TRUE);
664:
665: break;
666: }
667:
668: case MarkMessageCommand.MARK_AS_NOTSPAM: {
669: header.getAttributes().put("columba.spam", Boolean.FALSE);
670:
671: break;
672: }
673: case MarkMessageCommand.MARK_AS_DRAFT: {
674: flags.setDraft(true);
675:
676: break;
677: }
678: case MarkMessageCommand.MARK_AS_NOTDRAFT: {
679: flags.setDraft(false);
680:
681: break;
682: }
683: case MarkMessageCommand.MARK_AS_RECENT: {
684: flags.setRecent(true);
685:
686: break;
687: }
688: case MarkMessageCommand.MARK_AS_NOTRECENT: {
689: flags.setRecent(false);
690:
691: break;
692: }
693: }
694: setChanged(true);
695:
696: header.setFlags(flags);
697: getHeaderList().update(uid, header);
698:
699: fireMessageFlagChanged(uid, oldFlags, variant);
700: }
701:
702: /**
703: * @see org.columba.mail.folder.IMailbox#markMessage(java.lang.Object[],
704: * int)
705: */
706: public void markMessage(Object[] uids, int variant)
707: throws Exception {
708: for (int i = 0; i < uids.length; i++) {
709: if (exists(uids[i])) {
710: markMessage(uids[i], variant);
711:
712: }
713: }
714: }
715:
716: /** {@inheritDoc} */
717: public void expungeFolder() throws Exception {
718:
719: // get list of all uids
720: Object[] uids = getUids();
721:
722: for (int i = 0; i < uids.length; i++) {
723: Object uid = uids[i];
724:
725: if (uid == null) {
726: continue;
727: }
728:
729: // if message with uid doesn't exist -> skip
730: if (!exists(uid)) {
731: LOG.info("uid " + uid + " doesn't exist");
732:
733: continue;
734: }
735:
736: if (getFlags(uid).getDeleted()) {
737: // move message to trash if marked as expunged
738: LOG.info("removing uid=" + uid);
739:
740: // remove message
741: removeMessage(uid);
742: }
743: }
744: }
745:
746: /**
747: * Remove message from folder.
748: * <p>
749: *
750: * @author: fdietz This method was intentionally changed to public also it
751: * isn't accessed from outside. This is why it isn't found in
752: * IMailbox. Only the VirtualFolder uses this public call.
753: *
754: *
755: * @param uid
756: * UID identifying the message to remove
757: * @throws Exception
758: */
759: public void removeMessage(Object uid) throws Exception {
760: // remove from header-list
761: IColumbaHeader header = getHeaderList().remove(uid);
762:
763: // notify listeners
764: fireMessageRemoved(uid, header.getFlags());
765: }
766:
767: /** ****************************** IAttributeStorage *********************** */
768:
769: /**
770: * @return Returns the attributeStorage.
771: */
772: // public abstract IHeaderListStorage getHeaderListStorage();
773: /**
774: * @see org.columba.mail.folder.IMailbox#exists(java.lang.Object)
775: */
776: public boolean exists(Object uid) throws Exception {
777: return getHeaderList().exists(uid);
778: }
779:
780: /**
781: * @see org.columba.mail.folder.IMailbox#getUids()
782: */
783: public Object[] getUids() throws Exception {
784: return getHeaderList().getUids();
785: }
786:
787: /**
788: * @see org.columba.mail.folder.IMailbox#setAttribute(java.lang.Object,
789: * java.lang.String, java.lang.Object)
790: */
791: public void setAttribute(Object uid, String key, Object value)
792: throws Exception {
793:
794: IColumbaHeader header = getHeaderList().get(uid);
795:
796: header.getAttributes().put(key, value);
797:
798: getHeaderList().update(uid, header);
799:
800: // set folder changed flag
801: // -> if not, the header cache wouldn't notice that something
802: // -> has changed. And wouldn't save the changes.
803: setChanged(true);
804: }
805:
806: /**
807: * @see org.columba.mail.folder.IMailbox#getFlags(java.lang.Object)
808: */
809: public Flags getFlags(Object uid) throws Exception {
810: return getHeaderList().get(uid).getFlags();
811: }
812:
813: /**
814: * @see org.columba.mail.folder.IMailbox#getAttributes(java.lang.Object)
815: */
816: public Attributes getAttributes(Object uid) throws Exception {
817: return getHeaderList().get(uid).getAttributes();
818: }
819:
820: /**
821: * @see org.columba.mail.folder.IMailbox#getAttribute(java.lang.Object,
822: * java.lang.String)
823: */
824: public Object getAttribute(Object uid, String key) throws Exception {
825: return getHeaderList().get(uid).getAttributes().get(key);
826: }
827:
828: /**
829: * @return
830: */
831: public DefaultSearchEngine getSearchEngine() {
832: return this .searchEngine;
833: }
834:
835: /**
836: * @param filter
837: * @param uids
838: * @return
839: * @throws Exception
840: */
841: public Object[] searchMessages(IFilter filter, Object[] uids)
842: throws Exception {
843: // if there is no search engine, try the default one
844: if (getSearchEngine() == null)
845: return (new DefaultSearchEngine(this )).searchMessages(
846: filter, uids);
847: return getSearchEngine().searchMessages(filter, uids);
848: }
849:
850: /**
851: * @param filter
852: * @return
853: * @throws Exception
854: */
855: public Object[] searchMessages(IFilter filter) throws Exception {
856: // if there is no search engine, try the default one
857: if (getSearchEngine() == null)
858: return (new DefaultSearchEngine(this ))
859: .searchMessages(filter);
860: return getSearchEngine().searchMessages(filter);
861: }
862:
863: /**
864: * Set new search engine
865: *
866: * @see org.columba.mail.folder.search
867: *
868: * @param engine
869: * new search engine
870: */
871: public void setSearchEngine(DefaultSearchEngine engine) {
872: this .searchEngine = engine;
873: }
874:
875: /**
876: * TODO (@author fdietz): move this out-of-folder!
877: *
878: * @param header
879: * @param bodyStream
880: * @return
881: */
882: protected InputStream decodeStream(MimeHeader header,
883: InputStream bodyStream) {
884: String charsetName = header.getContentParameter("charset");
885: int encoding = header.getContentTransferEncoding();
886:
887: switch (encoding) {
888: case MimeHeader.QUOTED_PRINTABLE: {
889: bodyStream = new QuotedPrintableDecoderInputStream(
890: bodyStream);
891:
892: break;
893: }
894:
895: case MimeHeader.BASE64: {
896: bodyStream = new Base64DecoderInputStream(bodyStream);
897:
898: break;
899: }
900: }
901:
902: if (charsetName != null) {
903: Charset charset;
904:
905: try {
906: charset = Charset.forName(charsetName);
907: } catch (UnsupportedCharsetException e) {
908: charset = Charset.forName(System
909: .getProperty("file.encoding"));
910: }
911:
912: bodyStream = new CharsetDecoderInputStream(bodyStream,
913: charset);
914: }
915:
916: return bodyStream;
917: }
918:
919: /**
920: * @see org.columba.mail.folder.IMailbox#isReadOnly()
921: */
922: public boolean isReadOnly() {
923: return false;
924: }
925:
926: /**
927: * @return Returns the headerList.
928: */
929: public abstract IHeaderList getHeaderList() throws Exception;
930:
931: }
|