0001: // The contents of this file are subject to the Mozilla Public License Version
0002: // 1.1
0003: //(the "License"); you may not use this file except in compliance with the
0004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
0005: //
0006: //Software distributed under the License is distributed on an "AS IS" basis,
0007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0008: //for the specific language governing rights and
0009: //limitations under the License.
0010: //
0011: //The Original Code is "The Columba Project"
0012: //
0013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
0014: // Stich.
0015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
0016: //
0017: //All Rights Reserved.
0018:
0019: package org.columba.mail.folder.virtual;
0020:
0021: import java.io.InputStream;
0022: import java.util.ArrayList;
0023: import java.util.Arrays;
0024: import java.util.Collections;
0025: import java.util.Comparator;
0026: import java.util.Enumeration;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.logging.Logger;
0030:
0031: import javax.swing.JDialog;
0032:
0033: import org.columba.api.command.IWorkerStatusController;
0034: import org.columba.core.filter.Filter;
0035: import org.columba.core.filter.FilterCriteria;
0036: import org.columba.core.filter.FilterRule;
0037: import org.columba.core.filter.IFilter;
0038: import org.columba.core.filter.IFilterCriteria;
0039: import org.columba.core.filter.IFilterRule;
0040: import org.columba.core.xml.XmlElement;
0041: import org.columba.mail.config.FolderItem;
0042: import org.columba.mail.config.IFolderItem;
0043: import org.columba.mail.filter.MailFilterCriteria;
0044: import org.columba.mail.folder.AbstractLocalFolder;
0045: import org.columba.mail.folder.AbstractMessageFolder;
0046: import org.columba.mail.folder.FolderChildrenIterator;
0047: import org.columba.mail.folder.FolderFactory;
0048: import org.columba.mail.folder.IMailFolder;
0049: import org.columba.mail.folder.IMailbox;
0050: import org.columba.mail.folder.event.FolderListener;
0051: import org.columba.mail.folder.event.IFolderEvent;
0052: import org.columba.mail.folder.headercache.CachedHeaderfields;
0053: import org.columba.mail.folder.headercache.MemoryHeaderList;
0054: import org.columba.mail.folder.imap.IMAPFolder;
0055: import org.columba.mail.folder.mh.CachedMHFolder;
0056: import org.columba.mail.folder.search.DefaultSearchEngine;
0057: import org.columba.mail.gui.config.search.SearchFrame;
0058: import org.columba.mail.gui.frame.AbstractMailFrameController;
0059: import org.columba.mail.gui.tree.FolderTreeModel;
0060: import org.columba.mail.message.ColumbaHeader;
0061: import org.columba.mail.message.ICloseableIterator;
0062: import org.columba.mail.message.IHeaderList;
0063: import org.columba.ristretto.message.Attributes;
0064: import org.columba.ristretto.message.Flags;
0065: import org.columba.ristretto.message.Header;
0066: import org.columba.ristretto.message.MimeTree;
0067:
0068: /**
0069: * Virtual folder presenting search results and saving only references to
0070: * messages of "real" folders.
0071: * <p>
0072: * Almost all methods don't do anything here, because the we pass all operatins
0073: * to the source folders. This happens on the Command and CommandReference
0074: * abstraction level.
0075: * <p>
0076: *
0077: * @author fdietz
0078: *
0079: */
0080: public class VirtualFolder extends AbstractMessageFolder implements
0081: FolderListener {
0082: /** JDK 1.4+ logging framework logger, used for logging. */
0083: private static final Logger LOG = Logger
0084: .getLogger("org.columba.mail.folder.virtual"); //$NON-NLS-1$
0085:
0086: protected int nextUid;
0087:
0088: protected IHeaderList headerList;
0089:
0090: private boolean active;
0091:
0092: private IMailFolder sourceFolder;
0093:
0094: // only called by FolderTreeModel.createDirectories() and FolderTreeModel.add()
0095: public VirtualFolder(FolderItem item, String path) {
0096: super (item);
0097:
0098: headerList = new MemoryHeaderList();
0099:
0100: ensureValidFilterElement();
0101: }
0102:
0103: // public VirtualFolder(FolderItem item) {
0104: // super(item);
0105: //
0106: // headerList = new MemoryHeaderList();
0107: //
0108: // ensureValidFilterElement();
0109: // }
0110:
0111: public VirtualFolder(String name) {
0112: super (name, "VirtualFolder");
0113:
0114: IFolderItem item = getConfiguration();
0115: item.setString("property", "accessrights", "user");
0116: item.setString("property", "subfolder", "true");
0117: item.setString("property", "include_subfolders", "true");
0118: item.setString("property", "source_uid", "101");
0119:
0120: headerList = new MemoryHeaderList();
0121:
0122: ensureValidFilterElement();
0123: }
0124:
0125: public VirtualFolder(String name, IMailFolder sourceFolder) {
0126: this (name);
0127:
0128: this .sourceFolder = sourceFolder;
0129: }
0130:
0131: private void registerWithSource() {
0132: IMailFolder folder = getSourceFolder();
0133:
0134: folder.addFolderListener(this );
0135:
0136: if (isRecursive()) {
0137: FolderChildrenIterator it = new FolderChildrenIterator(
0138: folder);
0139:
0140: while (it.hasMoreChildren()) {
0141: IMailFolder next = it.nextChild();
0142:
0143: if (!(next instanceof VirtualFolder)
0144: && (next instanceof IMailbox)) {
0145: next.addFolderListener(this );
0146: }
0147: }
0148: }
0149: }
0150:
0151: private void unregisterWithSource() {
0152: IMailFolder folder = getSourceFolder();
0153:
0154: folder.removeFolderListener(this );
0155:
0156: if (isRecursive()) {
0157: FolderChildrenIterator it = new FolderChildrenIterator(
0158: folder);
0159:
0160: while (it.hasMoreChildren()) {
0161: IMailFolder next = it.nextChild();
0162:
0163: if (!(next instanceof VirtualFolder)) {
0164: next.removeFolderListener(this );
0165: }
0166: }
0167: }
0168: }
0169:
0170: /**
0171: * Ensures that there is at least one valid filter entry in the VFolder.
0172: */
0173: private void ensureValidFilterElement() {
0174: XmlElement filter = getConfiguration().getRoot().getElement(
0175: "filter");
0176:
0177: if (filter == null) {
0178: filter = new XmlElement("filter");
0179: filter.addAttribute("description", "new filter");
0180: filter.addAttribute("enabled", "true");
0181: getConfiguration().getRoot().addElement(filter);
0182: }
0183:
0184: if (filter.count() == 0) {
0185: XmlElement rules = new XmlElement("rules");
0186: rules.addAttribute("condition", "matchall");
0187:
0188: XmlElement criteria = new XmlElement("criteria");
0189: criteria.addAttribute("type", "Subject");
0190: criteria.addAttribute("headerfield", "Subject");
0191: criteria.addAttribute("criteria", "contains");
0192: criteria.addAttribute("pattern", "pattern");
0193: rules.addElement(criteria);
0194: filter.addElement(rules);
0195: }
0196: }
0197:
0198: protected Object generateNextUid() {
0199: return new Integer(nextUid++);
0200: }
0201:
0202: public void setNextUid(int next) {
0203: nextUid = next;
0204: }
0205:
0206: public JDialog showFilterDialog(
0207: AbstractMailFrameController frameController) {
0208: return new SearchFrame(frameController, this );
0209: }
0210:
0211: public boolean exists(Object uid) throws Exception {
0212: return headerList.exists(uid);
0213: }
0214:
0215: public IHeaderList getHeaderList() throws Exception {
0216: if (!active) {
0217: activate();
0218: } else {
0219: revalidateSearch();
0220: }
0221:
0222: return headerList;
0223: }
0224:
0225: /**
0226: *
0227: */
0228: private void revalidateSearch() {
0229: VirtualHeader h;
0230:
0231: // Analyze the Filter
0232: IFilter filter = (Filter) getFilter().clone();
0233: IFilterRule rule = filter.getFilterRule();
0234: for (int i = 0; i < rule.count(); i++) {
0235: IFilterCriteria c = rule.get(i);
0236: if (!c.getTypeString().equalsIgnoreCase("flags")) {
0237: rule.remove(i);
0238: i--;
0239: }
0240: }
0241:
0242: // If no flags filter the seach is still valid
0243: if (rule.count() == 0) {
0244: return;
0245: }
0246:
0247: // redo the seach for the flags criteria
0248: ICloseableIterator it = headerList.headerIterator();
0249: while (it.hasNext()) {
0250: h = (VirtualHeader) it.next();
0251:
0252: try {
0253: if (h.getSrcFolder().searchMessages(filter,
0254: new Object[] { h.getSrcUid() }).length == 0) {
0255: it.remove();
0256:
0257: // notify listeners
0258: fireMessageRemoved(h.getVirtualUid(), h.getFlags());
0259:
0260: }
0261: } catch (Exception e) {
0262: e.printStackTrace();
0263: }
0264: }
0265: it.close();
0266:
0267: }
0268:
0269: public void addSearchToHistory() throws Exception {
0270: VirtualFolder searchFolder = (VirtualFolder) FolderTreeModel
0271: .getInstance().getFolder("106");
0272:
0273: // only create new subfolders if we used the default "Search Folder"
0274: if (!searchFolder.equals(this )) {
0275: return;
0276: }
0277:
0278: // (tstich) reduced to 3 because all need to be
0279: // search when activated on startup
0280: // we only want 3 subfolders
0281: // -> if more children exist remove them
0282: if (searchFolder.getChildCount() >= 3) {
0283: AbstractMessageFolder child = (AbstractMessageFolder) searchFolder
0284: .getChildAt(0);
0285: child.removeFolder();
0286: }
0287:
0288: // create new subfolder
0289: String name = "search result";
0290: VirtualFolder newFolder = null;
0291:
0292: try {
0293: newFolder = (VirtualFolder) FolderFactory.getInstance()
0294: .createChild(searchFolder, name, "VirtualFolder");
0295: } catch (Exception ex) {
0296: ex.printStackTrace();
0297:
0298: return;
0299: }
0300:
0301: // if creation failed
0302: if (newFolder == null) {
0303: return;
0304: }
0305:
0306: // copy all properties to the subfolder
0307: int uid = getConfiguration().getInteger("property",
0308: "source_uid");
0309: boolean includes = getConfiguration().getBoolean("property",
0310: "include_subfolders");
0311:
0312: IFolderItem newFolderItem = newFolder.getConfiguration();
0313: newFolderItem.setInteger("property", "source_uid", uid);
0314: newFolderItem.setBoolean("property", "include_subfolders",
0315: includes);
0316:
0317: newFolderItem.getElement("filter").removeFromParent();
0318: newFolderItem.getRoot().addElement(
0319: (XmlElement) getConfiguration().getElement("filter")
0320: .clone());
0321:
0322: MailFilterCriteria newc = new MailFilterCriteria(new Filter(
0323: getConfiguration().getElement("filter"))
0324: .getFilterRule().get(0));
0325:
0326: /*
0327: * FilterCriteria c = new
0328: * Filter(getConfiguration().getElement("filter")) .getFilterRule()
0329: * .get( 0);
0330: *
0331: * FilterCriteria newc = new
0332: * Filter(getConfiguration().getElement("filter")) .getFilterRule()
0333: * .get( 0); newc.setCriteria(c.getCriteriaString());
0334: * newc.setHeaderItem(c.getHeaderItemString());
0335: * newc.setPattern(c.getPattern()); newc.setType(c.getType());
0336: */
0337:
0338: // lets find a good name for our new vfolder
0339: StringBuffer buf = new StringBuffer();
0340:
0341: if (newc.getTypeString().equalsIgnoreCase("flags")) {
0342: LOG.info("flags found"); //$NON-NLS-1$
0343:
0344: buf.append(newc.getTypeString());
0345: buf.append(" (");
0346: buf.append(newc.getCriteriaString());
0347: buf.append(" ");
0348: buf.append(newc.getPatternString());
0349: buf.append(")");
0350: } else if (newc.getTypeString().equalsIgnoreCase(
0351: "custom headerfield")) {
0352: buf.append(newc.getHeaderfieldString());
0353: buf.append(" (");
0354: buf.append(newc.getCriteriaString());
0355: buf.append(" ");
0356: buf.append(newc.getPatternString());
0357: buf.append(")");
0358: } else {
0359: buf.append(newc.getTypeString());
0360: buf.append(" (");
0361: buf.append(newc.getCriteriaString());
0362: buf.append(" ");
0363: buf.append(newc.getPatternString());
0364: buf.append(")");
0365: }
0366:
0367: newFolder.setName(buf.toString());
0368:
0369: // update tree-view
0370: FolderTreeModel.getInstance()
0371: .nodeStructureChanged(searchFolder);
0372:
0373: // update tree-node (for renaming the new folder)
0374: FolderTreeModel.getInstance().nodeChanged(newFolder);
0375: }
0376:
0377: protected void applySearch() throws Exception {
0378: IMailFolder srcFolder = getSourceFolder();
0379:
0380: XmlElement filter = getConfiguration().getRoot().getElement(
0381: "filter");
0382:
0383: if (filter == null) {
0384: filter = new XmlElement("filter");
0385: filter.addAttribute("description", "new filter");
0386: filter.addAttribute("enabled", "true");
0387:
0388: XmlElement rules = new XmlElement("rules");
0389: rules.addAttribute("condition", "match_all");
0390:
0391: XmlElement criteria = new XmlElement("criteria");
0392: criteria.addAttribute("type", "Subject");
0393: criteria.addAttribute("headerfield", "Subject");
0394: criteria.addAttribute("criteria", "contains");
0395: criteria.addAttribute("pattern", "pattern");
0396: rules.addElement(criteria);
0397: filter.addElement(rules);
0398: getConfiguration().getRoot().addElement(filter);
0399: }
0400:
0401: Filter f = new Filter(getConfiguration().getRoot().getElement(
0402: "filter"));
0403:
0404: applySearch(srcFolder, f);
0405: }
0406:
0407: /**
0408: * @return
0409: */
0410: IMailFolder getSourceFolder() {
0411:
0412: String uid = getConfiguration().getString("property",
0413: "source_uid");
0414:
0415: if (sourceFolder != null && sourceFolder.getId().equals(uid))
0416: return sourceFolder;
0417:
0418: IMailFolder folder = (IMailFolder) FolderTreeModel
0419: .getInstance().getFolder(uid);
0420:
0421: return folder;
0422: }
0423:
0424: protected void applySearch(IMailFolder parent, Filter filter)
0425: throws Exception {
0426:
0427: if (parent instanceof IMailbox) {
0428:
0429: IMailbox folder = (IMailbox) parent;
0430:
0431: // if the parent is a virtual folder the search cannot be applied directly
0432: // look for the correct uids by finding the first non virtual folder
0433:
0434: Object[] resultUids = null;
0435:
0436: if (folder instanceof VirtualFolder)
0437: resultUids = folder.searchMessages(filter, folder
0438: .getUids());
0439: else
0440: resultUids = folder.searchMessages(filter);
0441:
0442: String[] headerfields = CachedHeaderfields
0443: .getDefaultHeaderfields();
0444:
0445: if (resultUids != null) {
0446: for (int i = 0; i < resultUids.length; i++) {
0447: ColumbaHeader header = null;
0448:
0449: if (folder instanceof VirtualFolder) {
0450: // get source folder reference
0451: VirtualHeader virtualHeader = ((VirtualFolder) folder)
0452: .getVirtualHeader(resultUids[i]);
0453: IMailbox sourceFolder = virtualHeader
0454: .getSrcFolder();
0455: Object sourceUid = virtualHeader.getSrcUid();
0456:
0457: Header h = sourceFolder.getHeaderFields(
0458: sourceUid, headerfields);
0459: header = new ColumbaHeader(h);
0460: header.setAttributes(sourceFolder
0461: .getAttributes(sourceUid));
0462: header.setFlags(sourceFolder
0463: .getFlags(sourceUid));
0464: Object uid = add((ColumbaHeader) header,
0465: sourceFolder, sourceUid);
0466: fireMessageAdded(uid, getFlags(uid));
0467: } else {
0468: if (!folder.exists(resultUids[i]))
0469: continue;
0470:
0471: Header h = folder.getHeaderFields(
0472: resultUids[i], headerfields);
0473: header = new ColumbaHeader(h);
0474: header.setAttributes(folder
0475: .getAttributes(resultUids[i]));
0476: header.setFlags(folder.getFlags(resultUids[i]));
0477: Object uid = add(header, folder, resultUids[i]);
0478: fireMessageAdded(uid, getFlags(uid));
0479:
0480: }
0481:
0482: }
0483: }
0484:
0485: }
0486:
0487: if (isRecursive()) {
0488: for (Enumeration e = parent.children(); e.hasMoreElements();) {
0489: IMailFolder folder = (IMailFolder) e.nextElement();
0490:
0491: if (folder instanceof VirtualFolder) {
0492: continue;
0493: }
0494:
0495: applySearch(folder, filter);
0496: }
0497: }
0498: }
0499:
0500: private boolean isRecursive() {
0501: return Boolean.valueOf(
0502: getConfiguration().getString("property",
0503: "include_subfolders")).booleanValue();
0504: }
0505:
0506: public DefaultSearchEngine getSearchEngine() {
0507: return null;
0508: }
0509:
0510: public Filter getFilter() {
0511: return new Filter(getConfiguration().getRoot().getElement(
0512: "filter"));
0513: }
0514:
0515: public Object add(ColumbaHeader header, IMailbox source, Object uid)
0516: throws Exception {
0517: Object newUid = generateNextUid();
0518:
0519: // VirtualMessage m = new VirtualMessage(f, uid, index);
0520: VirtualHeader virtualHeader = new VirtualHeader(
0521: (ColumbaHeader) header, source, uid);
0522: virtualHeader.setVirtualUid(newUid);
0523:
0524: headerList.add(virtualHeader, newUid);
0525:
0526: return newUid;
0527: }
0528:
0529: /**
0530: * @see org.columba.modules.mail.folder.Folder#markMessage(Object[], int,
0531: * IMAPFolder)
0532: */
0533: public void markMessage(Object[] uids, int variant)
0534: throws Exception {
0535: List list = new ArrayList();
0536:
0537: // Check if all uids are still exisiting
0538: for (Object uid : uids) {
0539: if (exists(uid)) {
0540: list.add(uid);
0541: }
0542: }
0543: if (list.size() == 0)
0544: return;
0545:
0546: Collections.sort(list, new Comparator() {
0547:
0548: public int compare(Object o1, Object o2) {
0549: VirtualHeader h = (VirtualHeader) headerList.get(o1);
0550: String oV1 = h.getSrcFolder().getId();
0551:
0552: h = (VirtualHeader) headerList.get(o2);
0553: String oV2 = h.getSrcFolder().getId();
0554:
0555: return oV1.compareTo(oV2);
0556: }
0557: });
0558:
0559: List folderUids = new ArrayList(uids.length);
0560: Iterator it = list.iterator();
0561:
0562: VirtualHeader h = (VirtualHeader) headerList.get(it.next());
0563: ;
0564: folderUids.add(h.getSrcUid());
0565: IMailbox srcFolder = h.getSrcFolder();
0566:
0567: while (it.hasNext()) {
0568: h = (VirtualHeader) headerList.get(it.next());
0569:
0570: if (h.getSrcFolder() == srcFolder) {
0571: folderUids.add(h.getSrcUid());
0572: } else {
0573: srcFolder.markMessage(folderUids.toArray(), variant);
0574:
0575: // change to new folder
0576: srcFolder = h.getSrcFolder();
0577: folderUids.clear();
0578: folderUids.add(h.getSrcUid());
0579: }
0580: }
0581:
0582: srcFolder.markMessage(folderUids.toArray(), variant);
0583: }
0584:
0585: /**
0586: * @see org.columba.modules.mail.folder.Folder#remove(Object)
0587: */
0588: public void removeMessage(Object uid) throws Exception {
0589:
0590: // get source folder reference
0591: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0592: IMailbox sourceFolder = h.getSrcFolder();
0593: Object sourceUid = h.getSrcUid();
0594:
0595: // remove from source folder
0596: sourceFolder.removeMessage(sourceUid);
0597:
0598: // remove from virtual folder
0599: headerList.remove(uid);
0600:
0601: // notify listeners
0602: fireMessageRemoved(uid, getFlags(uid));
0603: }
0604:
0605: /**
0606: * @see org.columba.modules.mail.folder.Folder#getMimeTree(Object,
0607: * IMAPFolder)
0608: */
0609: public MimeTree getMimePartTree(Object uid) throws Exception {
0610: if (!exists(uid))
0611: return null;
0612:
0613: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0614: IMailbox sourceFolder = h.getSrcFolder();
0615: Object sourceUid = h.getSrcUid();
0616:
0617: return sourceFolder.getMimePartTree(sourceUid);
0618: }
0619:
0620: /**
0621: * Get virtual header.
0622: *
0623: * @param virtualUid
0624: * virtual uid
0625: * @return virtual header
0626: */
0627: public VirtualHeader getVirtualHeader(Object virtualUid) {
0628: return (VirtualHeader) headerList.get(virtualUid);
0629: }
0630:
0631: /**
0632: * @see org.columba.modules.mail.folder.Folder#searchMessages(Filter,
0633: * Object[], IWorkerStatusController)
0634: */
0635: public Object[] searchMessages(Filter filter, Object[] uids)
0636: throws Exception {
0637: if (!active) {
0638: activate();
0639: } else {
0640: revalidateSearch();
0641: }
0642:
0643: if (uids.length == 0)
0644: return new Object[0];
0645:
0646: List list = new ArrayList(Arrays.asList(uids));
0647:
0648: Collections.sort(list, new Comparator() {
0649:
0650: public int compare(Object o1, Object o2) {
0651: VirtualHeader h = (VirtualHeader) headerList.get(o1);
0652: String oV1 = h.getSrcFolder().getId();
0653:
0654: h = (VirtualHeader) headerList.get(o2);
0655: String oV2 = h.getSrcFolder().getId();
0656:
0657: return oV1.compareTo(oV2);
0658: }
0659: });
0660:
0661: List resultList = new ArrayList();
0662:
0663: List virtualHeader = new ArrayList();
0664: VirtualHeader h = (VirtualHeader) headerList.get(list.get(0));
0665: IMailbox sourceFolder = h.getSrcFolder();
0666: virtualHeader.add(h);
0667:
0668: for (int i = 1; i < uids.length; i++) {
0669: h = (VirtualHeader) headerList.get(list.get(i));
0670:
0671: if (h.getSrcFolder() != sourceFolder
0672: || i == uids.length - 1) {
0673: // Now we can search this folder since no mail from
0674: // this folder will come in the list
0675:
0676: Object[] srcUids = new Object[virtualHeader.size()];
0677:
0678: // Create a src uid array
0679: for (int j = 0; j < virtualHeader.size(); j++) {
0680: srcUids[j] = ((VirtualHeader) virtualHeader.get(j))
0681: .getSrcUid();
0682: }
0683:
0684: // search the src folder with the src uid array
0685: Object[] resultUids = sourceFolder.searchMessages(
0686: filter, srcUids);
0687:
0688: // Convert the src uids back to virtual uids
0689: if ((resultUids != null) && (resultUids.length > 0)) {
0690: Object[] virtualUids = new Object[resultUids.length];
0691: for (int j = 0; j < resultUids.length; j++) {
0692: virtualUids[j] = srcUidToVirtualUid(
0693: sourceFolder, resultUids[j]);
0694: }
0695:
0696: // Add all found virtual uids to the result
0697: resultList.addAll(Arrays.asList(virtualUids));
0698: }
0699:
0700: virtualHeader.clear();
0701: }
0702:
0703: // Add this header to the list for later searching
0704: virtualHeader.add(h);
0705: sourceFolder = h.getSrcFolder();
0706: }
0707: if (virtualHeader.size() > 0) {
0708: // Now we can search this folder since no mail from
0709: // this folder will come in the list
0710:
0711: Object[] srcUids = new Object[virtualHeader.size()];
0712:
0713: // Create a src uid array
0714: for (int j = 0; j < virtualHeader.size(); j++) {
0715: srcUids[j] = ((VirtualHeader) virtualHeader.get(j))
0716: .getSrcUid();
0717: }
0718:
0719: // search the src folder with the src uid array
0720: Object[] resultUids = sourceFolder.searchMessages(filter,
0721: srcUids);
0722:
0723: // Convert the src uids back to virtual uids
0724: if ((resultUids != null) && (resultUids.length > 0)) {
0725: Object[] virtualUids = new Object[resultUids.length];
0726: for (int j = 0; j < resultUids.length; j++) {
0727: virtualUids[j] = srcUidToVirtualUid(sourceFolder,
0728: resultUids[j]);
0729: }
0730:
0731: // Add all found virtual uids to the result
0732: resultList.addAll(Arrays.asList(virtualUids));
0733: }
0734:
0735: virtualHeader.clear();
0736: }
0737:
0738: return resultList.toArray();
0739: }
0740:
0741: public Object[] searchMessages(Filter filter) throws Exception {
0742:
0743: return searchMessages(filter, getUids());
0744: }
0745:
0746: /**
0747: * @see org.columba.modules.mail.folder.FolderTreeNode#instanceNewChildNode(AdapterNode,
0748: * FolderItem)
0749: */
0750: public String getDefaultChild() {
0751: return null;
0752: }
0753:
0754: public static XmlElement getDefaultProperties() {
0755: XmlElement props = new XmlElement("property");
0756: props.addAttribute("accessrights", "user");
0757: props.addAttribute("subfolder", "true");
0758: props.addAttribute("include_subfolders", "true");
0759: props.addAttribute("source_uid", "101");
0760:
0761: return props;
0762: }
0763:
0764: /*
0765: * public MailFolderCommandReference getCommandReference(
0766: * MailFolderCommandReference r) { MailFolderCommandReference[] newReference =
0767: * null;
0768: *
0769: * Object[] uids = r[0].getUids(); // if we didn't pass uid array here, use
0770: * all message in this virtual // folder try { if (uids == null) { uids =
0771: * getUids(); } } catch (Exception e1) { e1.printStackTrace(); }
0772: *
0773: * if (uids == null) { return r; }
0774: *
0775: * Hashtable list = new Hashtable();
0776: *
0777: * for (int i = 0; i < uids.length; i++) { VirtualHeader virtualHeader =
0778: * (VirtualHeader) headerList .get(uids[i]); AbstractMessageFolder srcFolder =
0779: * virtualHeader.getSrcFolder(); Object srcUid = virtualHeader.getSrcUid();
0780: *
0781: * if (list.containsKey(srcFolder)) { // bucket for this folder exists
0782: * already } else { // create new bucket for this folder list.put(srcFolder,
0783: * new Vector()); }
0784: *
0785: * List v = (Vector) list.get(srcFolder); v.add(srcUid); }
0786: *
0787: * newReference = new MailFolderCommandReference[list.size() + 2];
0788: *
0789: * int i = 0;
0790: *
0791: * for (Enumeration e = list.keys(); e.hasMoreElements();) {
0792: * AbstractMessageFolder srcFolder = (AbstractMessageFolder)
0793: * e.nextElement(); List v = (Vector) list.get(srcFolder);
0794: *
0795: * newReference[i] = new MailFolderCommandReference(srcFolder);
0796: *
0797: * Object[] uidArray = new Object[v.size()]; ((Vector)
0798: * v).copyInto(uidArray); newReference[i].setUids(uidArray);
0799: * newReference[i].setMarkVariant(r[0].getMarkVariant());
0800: * newReference[i].setMessage(r[0].getMessage());
0801: * newReference[i].setDestFile(r[0].getDestFile());
0802: *
0803: * i++; }
0804: *
0805: * if (r.length > 1) { newReference[i] = new
0806: * MailFolderCommandReference((AbstractMessageFolder) r[1] .getFolder()); }
0807: * else { newReference[i] = null; }
0808: *
0809: * newReference[i + 1] = r[0];
0810: *
0811: * return newReference; }
0812: */
0813:
0814: /**
0815: * @see org.columba.mail.folder.FolderTreeNode#tryToGetLock(java.lang.Object)
0816: */
0817: public boolean tryToGetLock(Object locker) {
0818: // First try to get the lock of the virtual folder
0819: boolean success = super .tryToGetLock(locker);
0820: if (!success)
0821: return false;
0822:
0823: // We need to get the locks of all folders
0824: IMailFolder folder = getSourceFolder();
0825:
0826: success &= folder.tryToGetLock(locker);
0827:
0828: if (success && isRecursive()) {
0829: FolderChildrenIterator it = new FolderChildrenIterator(
0830: folder);
0831:
0832: while (success && it.hasMoreChildren()) {
0833: IMailFolder next = it.nextChild();
0834:
0835: if (!(next instanceof VirtualFolder)
0836: && (next instanceof IMailbox)) {
0837: success &= next.tryToGetLock(locker);
0838: }
0839: }
0840: }
0841:
0842: if (!success) {
0843: releaseLock(locker);
0844: }
0845:
0846: return success;
0847: }
0848:
0849: /**
0850: * @see org.columba.mail.folder.AbstractFolder#releaseLock(java.lang.Object)
0851: */
0852: public void releaseLock(Object locker) {
0853: super .releaseLock(locker);
0854:
0855: IMailFolder folder = getSourceFolder();
0856:
0857: folder.releaseLock(locker);
0858:
0859: if (isRecursive()) {
0860: FolderChildrenIterator it = new FolderChildrenIterator(
0861: folder);
0862:
0863: while (it.hasMoreChildren()) {
0864: IMailFolder next = it.nextChild();
0865:
0866: if (!(next instanceof VirtualFolder)
0867: && (next instanceof IMailbox)) {
0868: next.releaseLock(locker);
0869: }
0870: }
0871: }
0872:
0873: }
0874:
0875: /*
0876: * (non-Javadoc)
0877: *
0878: * @see org.columba.mail.folder.Folder#getUids(org.columba.api.command.IWorkerStatusController)
0879: */
0880: public Object[] getUids() throws Exception {
0881: if (!active) {
0882: activate();
0883: }
0884:
0885: return headerList.getUids();
0886: }
0887:
0888: protected Object srcUidToVirtualUid(IMailFolder srcFolder,
0889: Object uid) {
0890: ICloseableIterator it = headerList.headerIterator();
0891:
0892: while (it.hasNext()) {
0893: VirtualHeader h = (VirtualHeader) it.next();
0894: if (h.getSrcUid().equals(uid)
0895: && h.getSrcFolder().equals(srcFolder)) {
0896: it.close();
0897: return h.getVirtualUid();
0898: }
0899:
0900: }
0901: it.close();
0902:
0903: return null;
0904: }
0905:
0906: /*
0907: * (non-Javadoc)
0908: *
0909: * @see org.columba.mail.folder.IMailbox#addMessage(java.io.InputStream)
0910: */
0911: public Object addMessage(InputStream in) throws Exception {
0912: // not supported
0913: return null;
0914: }
0915:
0916: /*
0917: * (non-Javadoc)
0918: *
0919: * @see org.columba.mail.folder.IMailbox#getAttribute(java.lang.Object,
0920: * java.lang.String)
0921: */
0922: public Object getAttribute(Object uid, String key) throws Exception {
0923: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0924: IMailbox sourceFolder = h.getSrcFolder();
0925: Object sourceUid = h.getSrcUid();
0926:
0927: return sourceFolder.getAttribute(sourceUid, key);
0928: }
0929:
0930: /*
0931: * (non-Javadoc)
0932: *
0933: * @see org.columba.mail.folder.IMailbox#getFlags(java.lang.Object)
0934: */
0935: public Flags getFlags(Object uid) throws Exception {
0936:
0937: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0938: IMailbox sourceFolder = h.getSrcFolder();
0939:
0940: Object sourceUid = h.getSrcUid();
0941:
0942: return sourceFolder.getFlags(sourceUid);
0943: }
0944:
0945: /*
0946: * (non-Javadoc)
0947: *
0948: * @see org.columba.mail.folder.IMailbox#getHeaderFields(java.lang.Object,
0949: * java.lang.String[])
0950: */
0951: public Header getHeaderFields(Object uid, String[] keys)
0952: throws Exception {
0953:
0954: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0955: IMailbox sourceFolder = h.getSrcFolder();
0956: Object sourceUid = h.getSrcUid();
0957:
0958: return sourceFolder.getHeaderFields(sourceUid, keys);
0959: }
0960:
0961: /*
0962: * (non-Javadoc)
0963: *
0964: * @see org.columba.mail.folder.IMailbox#getMessageSourceStream(java.lang.Object)
0965: */
0966: public InputStream getMessageSourceStream(Object uid)
0967: throws Exception {
0968:
0969: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0970: IMailbox sourceFolder = h.getSrcFolder();
0971: Object sourceUid = h.getSrcUid();
0972:
0973: return sourceFolder.getMessageSourceStream(sourceUid);
0974: }
0975:
0976: /*
0977: * (non-Javadoc)
0978: *
0979: * @see org.columba.mail.folder.IMailbox#getMimePartBodyStream(java.lang.Object,
0980: * java.lang.Integer[])
0981: */
0982: public InputStream getMimePartBodyStream(Object uid,
0983: Integer[] address) throws Exception {
0984:
0985: VirtualHeader h = (VirtualHeader) headerList.get(uid);
0986: IMailbox sourceFolder = h.getSrcFolder();
0987: Object sourceUid = h.getSrcUid();
0988:
0989: return sourceFolder.getMimePartBodyStream(sourceUid, address);
0990: }
0991:
0992: /*
0993: * (non-Javadoc)
0994: *
0995: * @see org.columba.mail.folder.IMailbox#getMimePartSourceStream(java.lang.Object,
0996: * java.lang.Integer[])
0997: */
0998: public InputStream getMimePartSourceStream(Object uid,
0999: Integer[] address) throws Exception {
1000:
1001: VirtualHeader h = (VirtualHeader) headerList.get(uid);
1002: IMailbox sourceFolder = h.getSrcFolder();
1003: Object sourceUid = h.getSrcUid();
1004:
1005: return sourceFolder.getMimePartSourceStream(sourceUid, address);
1006: }
1007:
1008: /**
1009: *
1010: * VirtualFolder doesn't allow adding messages, in comparison to other
1011: * regular mailbox folders.
1012: *
1013: * @see org.columba.mail.folder.FolderTreeNode#supportsAddMessage()
1014: */
1015: public boolean supportsAddMessage() {
1016: return false;
1017: }
1018:
1019: /**
1020: * Virtual folders can only accept other Virtual folders as childs.
1021: *
1022: * @param newFolderType
1023: * a folder to check if it is a Virtual folder.
1024: * @return true if the folder is a VirtualFolder; false otherwise.
1025: */
1026: public boolean supportsAddFolder(String newFolderType) {
1027: return (newFolderType.equals(getType()));
1028: }
1029:
1030: public void innerCopy(IMailbox destFolder, Object[] uids)
1031: throws Exception {
1032: List list = new ArrayList();
1033:
1034: // Check if all uids are still exisiting
1035: for (Object uid : uids) {
1036: if (exists(uid)) {
1037: list.add(uid);
1038: }
1039: }
1040: if (list.size() == 0)
1041: return;
1042:
1043: Collections.sort(list, new Comparator() {
1044:
1045: public int compare(Object o1, Object o2) {
1046: VirtualHeader h = (VirtualHeader) headerList.get(o1);
1047: String oV1 = h.getSrcFolder().getId();
1048:
1049: h = (VirtualHeader) headerList.get(o2);
1050: String oV2 = h.getSrcFolder().getId();
1051:
1052: return oV1.compareTo(oV2);
1053: }
1054: });
1055:
1056: List folderUids = new ArrayList(uids.length);
1057: Iterator it = list.iterator();
1058:
1059: VirtualHeader h = (VirtualHeader) headerList.get(it.next());
1060: ;
1061: folderUids.add(h.getSrcUid());
1062: IMailbox srcFolder = h.getSrcFolder();
1063:
1064: while (it.hasNext()) {
1065: h = (VirtualHeader) headerList.get(it.next());
1066:
1067: if (h.getSrcFolder() == srcFolder) {
1068: folderUids.add(h.getSrcUid());
1069: } else {
1070: srcFolder.innerCopy(destFolder, folderUids.toArray());
1071:
1072: // change to new folder
1073: srcFolder = h.getSrcFolder();
1074: folderUids.clear();
1075: folderUids.add(h.getSrcUid());
1076: }
1077: }
1078:
1079: // Copy the rest
1080: srcFolder.innerCopy(destFolder, folderUids.toArray());
1081: }
1082:
1083: public void setAttribute(Object uid, String key, Object value)
1084: throws Exception {
1085: // get header with UID
1086: /*
1087: * ColumbaHeader header = (ColumbaHeader) headerList.get(uid);
1088: * header.getAttributes().put(key, value);
1089: */
1090:
1091: VirtualHeader h = (VirtualHeader) headerList.get(uid);
1092: h.getAttributes().put(key, value);
1093: IMailbox sourceFolder = h.getSrcFolder();
1094: Object sourceUid = h.getSrcUid();
1095:
1096: sourceFolder.setAttribute(sourceUid, key, value);
1097: }
1098:
1099: public Attributes getAttributes(Object uid) throws Exception {
1100: VirtualHeader h = (VirtualHeader) headerList.get(uid);
1101: IMailbox sourceFolder = h.getSrcFolder();
1102: Object sourceUid = h.getSrcUid();
1103:
1104: return sourceFolder.getAttributes(sourceUid);
1105:
1106: /*
1107: * if (getHeaderList().containsKey(uid)) { return
1108: * getHeaderList().get(uid).getAttributes(); } else { return null; }
1109: */
1110: }
1111:
1112: /*
1113: * (non-Javadoc)
1114: *
1115: * @see org.columba.mail.folder.IMailbox#addMessage(java.io.InputStream,
1116: * org.columba.ristretto.message.Attributes)
1117: */
1118: public Object addMessage(InputStream in, Attributes attributes,
1119: Flags flags) throws Exception {
1120:
1121: // not supported
1122:
1123: return null;
1124: }
1125:
1126: /**
1127: * @see org.columba.mail.folder.AbstractFolder#supportsMove()
1128: */
1129: public boolean supportsMove() {
1130: return true;
1131: }
1132:
1133: /**
1134: * @see org.columba.mail.folder.IMailbox#getAllHeaderFields(java.lang.Object)
1135: */
1136: public Header getAllHeaderFields(Object uid) throws Exception {
1137: VirtualHeader h = (VirtualHeader) headerList.get(uid);
1138: IMailbox sourceFolder = h.getSrcFolder();
1139: Object sourceUid = h.getSrcUid();
1140:
1141: return sourceFolder.getAllHeaderFields(sourceUid);
1142: }
1143:
1144: /**
1145: * @see org.columba.mail.folder.IMailbox#expungeFolder()
1146: */
1147: public void expungeFolder() throws Exception {
1148: IMailFolder srcFolder = getSourceFolder();
1149:
1150: boolean isInclude = Boolean.valueOf(
1151: getConfiguration().getString("property",
1152: "include_subfolders")).booleanValue();
1153:
1154: if (isInclude) {
1155: recursiveExpunge(srcFolder);
1156: } else {
1157: if (srcFolder instanceof IMailbox)
1158: ((IMailbox) srcFolder).expungeFolder();
1159: }
1160: }
1161:
1162: private void recursiveExpunge(IMailFolder srcFolder)
1163: throws Exception {
1164: IMailFolder folder;
1165:
1166: if (srcFolder instanceof IMailbox)
1167: ((IMailbox) srcFolder).expungeFolder();
1168:
1169: for (Enumeration e = srcFolder.children(); e.hasMoreElements();) {
1170: folder = (IMailFolder) e.nextElement();
1171:
1172: if (folder instanceof VirtualFolder) {
1173: continue;
1174: }
1175:
1176: recursiveExpunge(folder);
1177: }
1178:
1179: }
1180:
1181: /*
1182: * (non-Javadoc)
1183: *
1184: * @see org.columba.mail.folder.IMailFolder#getRootFolder()
1185: */
1186: public IMailFolder getRootFolder() {
1187: return getSourceFolder().getRootFolder();
1188: }
1189:
1190: /*
1191: * (non-Javadoc)
1192: *
1193: * @see org.columba.mail.folder.event.IFolderListener#messageAdded(org.columba.mail.folder.event.IFolderEvent)
1194: */
1195: public void messageAdded(IFolderEvent e) {
1196: // deactivate the folder
1197: deactivate();
1198: return;
1199: /*
1200: * AbstractMessageFolder folder = (AbstractMessageFolder)e.getSource();
1201: *
1202: * try { Object[] resultUids = folder.searchMessages(getFilter(), new
1203: * Object[] {e.getChanges()});
1204: *
1205: * if( resultUids.length > 0 ) { Header h =
1206: * folder.getHeaderFields(resultUids[0],
1207: * CachedHeaderfields.getDefaultHeaderfields()); ColumbaHeader header =
1208: * new ColumbaHeader(h);
1209: * header.setAttributes(folder.getAttributes(resultUids[0]));
1210: * header.setFlags(folder.getFlags(resultUids[0]));
1211: *
1212: * Object uid = add(header, folder, resultUids[0]);
1213: * fireMessageAdded(uid, getFlags(uid)); } } catch (Exception e1) {
1214: * e1.printStackTrace(); }
1215: */
1216: }
1217:
1218: /*
1219: * (non-Javadoc)
1220: *
1221: * @see org.columba.mail.folder.event.IFolderListener#messageRemoved(org.columba.mail.folder.event.IFolderEvent)
1222: */
1223: public void messageRemoved(IFolderEvent e) {
1224: Object srcUid = e.getChanges();
1225:
1226: Object vUid = srcUidToVirtualUid((IMailFolder) e.getSource(),
1227: srcUid);
1228: if (vUid != null) {
1229: headerList.remove(vUid);
1230:
1231: // notify listeners
1232: fireMessageRemoved(vUid, null);
1233: }
1234: }
1235:
1236: protected boolean hasFlagsCriteria() {
1237: boolean result = false;
1238:
1239: IFilterRule rule = getFilter().getFilterRule();
1240:
1241: for (int i = 0; i < rule.count() && !result; i++) {
1242: result = rule.get(i).getTypeString().equalsIgnoreCase(
1243: "FLAGS");
1244: }
1245:
1246: return result;
1247: }
1248:
1249: /*
1250: * (non-Javadoc)
1251: *
1252: * @see org.columba.mail.folder.event.IFolderListener#messageFlagChanged(org.columba.mail.folder.event.IFolderEvent)
1253: */
1254: public void messageFlagChanged(IFolderEvent e) {
1255: Object virtualUid = srcUidToVirtualUid((IMailFolder) e
1256: .getSource(), e.getChanges());
1257:
1258: if (virtualUid == null && hasFlagsCriteria()) {
1259:
1260: AbstractMessageFolder folder = (AbstractMessageFolder) e
1261: .getSource();
1262: try {
1263: Object[] resultUids = folder.searchMessages(
1264: getFilter(), new Object[] { e.getChanges() });
1265:
1266: if (resultUids.length > 0) {
1267: Header h = folder
1268: .getHeaderFields(resultUids[0],
1269: CachedHeaderfields
1270: .getDefaultHeaderfields());
1271: ColumbaHeader header = new ColumbaHeader(h);
1272: header.setAttributes(folder
1273: .getAttributes(resultUids[0]));
1274: header.setFlags(folder.getFlags(resultUids[0]));
1275:
1276: Object uid = add(header, folder, resultUids[0]);
1277: fireMessageAdded(uid, getFlags(uid));
1278: }
1279: } catch (Exception e1) {
1280: e1.printStackTrace();
1281: }
1282: }
1283:
1284: if (virtualUid != null) {
1285: // Update the Virtual Header
1286:
1287: VirtualHeader h = (VirtualHeader) headerList
1288: .get(virtualUid);
1289: AbstractMessageFolder folder = (AbstractMessageFolder) e
1290: .getSource();
1291: try {
1292: h.setAttributes(folder.getAttributes(e.getChanges()));
1293: h.setFlags(folder.getFlags(e.getChanges()));
1294:
1295: updateMailFolderInfo(e.getOldFlags(), e.getParameter());
1296: } catch (Exception e1) {
1297: }
1298:
1299: // fire updates
1300: fireMessageFlagChanged(virtualUid, e.getOldFlags(), e
1301: .getParameter());
1302: }
1303: }
1304:
1305: /*
1306: * (non-Javadoc)
1307: *
1308: * @see org.columba.mail.folder.event.IFolderListener#folderPropertyChanged(org.columba.mail.folder.event.IFolderEvent)
1309: */
1310: public void folderPropertyChanged(IFolderEvent e) {
1311: // don't care
1312: }
1313:
1314: /*
1315: * (non-Javadoc)
1316: *
1317: * @see org.columba.mail.folder.event.IFolderListener#folderAdded(org.columba.mail.folder.event.IFolderEvent)
1318: */
1319: public void folderAdded(IFolderEvent e) {
1320: if (isRecursive() && !(e.getChanges() instanceof VirtualFolder)) {
1321: AbstractMessageFolder folder = (AbstractMessageFolder) e
1322: .getChanges();
1323: folder.addFolderListener(this );
1324: }
1325: }
1326:
1327: /*
1328: * (non-Javadoc)
1329: *
1330: * @see org.columba.mail.folder.event.IFolderListener#folderRemoved(org.columba.mail.folder.event.IFolderEvent)
1331: */
1332: public void folderRemoved(IFolderEvent e) {
1333: AbstractMessageFolder folder = (AbstractMessageFolder) e
1334: .getChanges();
1335: folder.removeFolderListener(this );
1336: }
1337:
1338: /**
1339: *
1340: */
1341: public void activate() throws Exception {
1342: if (active)
1343: return;
1344:
1345: LOG.fine("Activating virtual folder " + getName());
1346: getMessageFolderInfo().reset();
1347: applySearch();
1348: registerWithSource();
1349: active = true;
1350: }
1351:
1352: public void deactivate() {
1353: active = false;
1354: headerList.clear();
1355: getMessageFolderInfo().reset();
1356:
1357: unregisterWithSource();
1358: }
1359:
1360: /*
1361: * (non-Javadoc)
1362: *
1363: * @see org.columba.mail.folder.IMailFolder#removeFolder()
1364: */
1365: public void removeFolder() throws Exception {
1366: if (active) {
1367: deactivate();
1368: }
1369: super .removeFolder();
1370: }
1371:
1372: /**
1373: * @see org.columba.mail.folder.AbstractMessageFolder#getLastSelection()
1374: */
1375: public Object getLastSelection() {
1376: // not supported by virtual folder
1377: return null;
1378: }
1379:
1380: }
|