Search in sources :

Example 1 with ZimbraQueryHitResults

use of com.zimbra.common.mailbox.ZimbraQueryHitResults in project zm-mailbox by Zimbra.

the class ImapHandler method doTHREAD.

private boolean doTHREAD(String tag, ImapSearch i4search, boolean byUID) throws IOException, ImapException {
    if (!checkState(tag, State.SELECTED)) {
        return true;
    }
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    boolean requiresMODSEQ = i4search.requiresMODSEQ();
    if (requiresMODSEQ) {
        activateExtension(ImapExtension.CONDSTORE);
    }
    // MUST reject any such command with the tagged BAD response."
    if (requiresMODSEQ && !sessionActivated(ImapExtension.CONDSTORE)) {
        throw new ImapParseException(tag, "NOMODSEQ", "cannot THREAD MODSEQ in this mailbox", true);
    }
    LinkedHashMap<Integer, List<ImapMessage>> threads = new LinkedHashMap<Integer, List<ImapMessage>>();
    try {
        // RFC 5256 3: "The searched messages are sorted by base subject and then
        // by the sent date.  The messages are then split into separate
        // threads, with each thread containing messages with the same
        // base subject text.  Finally, the threads are sorted by the
        // sent date of the first message in the thread."
        ZimbraQueryHitResults zqr = runSearch(i4search, i4folder, SortBy.DATE_ASC, SearchParams.Fetch.PARENT);
        try {
            for (ZimbraQueryHit hit = zqr.getNext(); hit != null; hit = zqr.getNext()) {
                ImapMessage i4msg = i4folder.getById(hit.getItemId());
                if (i4msg == null || i4msg.isExpunged()) {
                    continue;
                }
                int parentId = hit.getParentId();
                if (parentId <= 0) {
                    threads.put(-i4msg.msgId, Arrays.asList(i4msg));
                    continue;
                }
                List<ImapMessage> contents = threads.get(parentId);
                if (contents == null) {
                    (contents = new LinkedList<ImapMessage>()).add(i4msg);
                    threads.put(parentId, contents);
                } else {
                    contents.add(i4msg);
                }
            }
        } finally {
            zqr.close();
        }
    } catch (ServiceException e) {
        ZimbraLog.imap.warn("THREAD failed", e);
        sendNO(tag, "THREAD failed");
        return true;
    }
    StringBuilder result = new StringBuilder("THREAD");
    if (!threads.isEmpty()) {
        result.append(' ');
        for (List<ImapMessage> thread : threads.values()) {
            // ORDEREDSUBJECT: "(A)" for singletons, "(A B)" for pairs, "(A (B)(C)(D)(E))" for larger threads
            Iterator<ImapMessage> it = thread.iterator();
            result.append('(').append(getMessageId(it.next(), byUID));
            if (it.hasNext()) {
                result.append(' ');
                if (thread.size() == 2) {
                    result.append(getMessageId(it.next(), byUID));
                } else {
                    while (it.hasNext()) {
                        result.append('(').append(getMessageId(it.next(), byUID)).append(')');
                    }
                }
            }
            result.append(')');
        }
    }
    sendUntagged(result.toString());
    sendNotifications(false, false);
    sendOK(tag, (byUID ? "UID " : "") + "THREAD completed");
    return true;
}
Also used : ZimbraQueryHit(com.zimbra.common.mailbox.ZimbraQueryHit) LinkedHashMap(java.util.LinkedHashMap) ZimbraQueryHitResults(com.zimbra.common.mailbox.ZimbraQueryHitResults) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Example 2 with ZimbraQueryHitResults

use of com.zimbra.common.mailbox.ZimbraQueryHitResults in project zm-mailbox by Zimbra.

the class TestZClient method testImapSearch.

@Test
public void testImapSearch() throws Exception {
    ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME);
    Mailbox mbox = TestUtil.getMailbox(USER_NAME);
    ZTag tag = zmbox.createTag("testImapSearch tag", Color.blue);
    int msgId = Integer.valueOf(TestUtil.addMessage(zmbox, "testImapSearch message"));
    mbox.alterTag(null, msgId, Type.MESSAGE, FlagInfo.UNREAD, false, null);
    mbox.alterTag(null, msgId, Type.MESSAGE, tag.getName(), true, null);
    ZSearchParams params = new ZSearchParams("testImapSearch");
    params.setMailItemTypes(Sets.newHashSet(MailItemType.MESSAGE));
    params.setFetch(Fetch.all);
    params.setZimbraFetchMode(ZimbraFetchMode.IMAP);
    ZimbraQueryHitResults results = zmbox.searchImap(null, params);
    Message msg = mbox.getMessageById(null, msgId);
    verifyImapSearchResults(results, msgId, msg.getImapUid(), msg.getParentId(), msg.getModifiedSequence(), MailItemType.MESSAGE, msg.getFlagBitmask(), new String[] { tag.getId() }, true);
    params.setZimbraFetchMode(ZimbraFetchMode.MODSEQ);
    results = zmbox.searchImap(null, params);
    verifyImapSearchResults(results, msgId, -1, msg.getParentId(), msg.getModifiedSequence(), MailItemType.MESSAGE, msg.getFlagBitmask(), new String[] { tag.getId() }, true);
    params.setZimbraFetchMode(ZimbraFetchMode.IDS);
    results = zmbox.searchImap(null, params);
    verifyImapSearchResults(results, msgId, -1, -1, -1, null, -1, null, false);
    // verify that setting the expandResult parameter also returns the necessary fields
    params.setFetch(Fetch.all);
    params.setZimbraFetchMode(ZimbraFetchMode.IMAP);
    results = zmbox.searchImap(null, params);
    verifyImapSearchResults(results, msgId, msg.getImapUid(), msg.getParentId(), msg.getModifiedSequence(), MailItemType.MESSAGE, msg.getFlagBitmask(), new String[] { tag.getId() }, true);
}
Also used : ZimbraQueryHitResults(com.zimbra.common.mailbox.ZimbraQueryHitResults) ZMailbox(com.zimbra.client.ZMailbox) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZMailbox(com.zimbra.client.ZMailbox) ImapMessage(com.zimbra.cs.imap.ImapMessage) ZMessage(com.zimbra.client.ZMessage) ZOutgoingMessage(com.zimbra.client.ZMailbox.ZOutgoingMessage) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) Message(com.zimbra.cs.mailbox.Message) ZSearchParams(com.zimbra.client.ZSearchParams) ZTag(com.zimbra.client.ZTag) ZMountpoint(com.zimbra.client.ZMountpoint) Test(org.junit.Test)

Example 3 with ZimbraQueryHitResults

use of com.zimbra.common.mailbox.ZimbraQueryHitResults in project zm-mailbox by Zimbra.

the class TestZClient method testImapSearchContact.

@Test
public void testImapSearchContact() throws Exception {
    ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME);
    Mailbox mbox = TestUtil.getMailbox(USER_NAME);
    ZTag tag = zmbox.createTag("testImapSearch tag", Color.blue);
    ZFolder folder = TestUtil.createFolder(zmbox, "/testImapSearch", ZFolder.View.contact);
    Contact contact = TestUtil.createContact(mbox, folder.getFolderIdInOwnerMailbox(), "testImapSearch@test.local");
    int contactId = contact.getId();
    mbox.alterTag(null, contactId, Type.CONTACT, FlagInfo.FLAGGED, true, null);
    mbox.alterTag(null, contactId, Type.CONTACT, tag.getName(), true, null);
    ZSearchParams params = new ZSearchParams("testImapSearch");
    params.setMailItemTypes(Sets.newHashSet(MailItemType.CONTACT));
    params.setZimbraFetchMode(ZimbraFetchMode.IMAP);
    ZimbraQueryHitResults results = zmbox.searchImap(null, params);
    verifyImapSearchResults(results, contactId, contact.getImapUid(), contact.getParentId(), contact.getModifiedSequence(), MailItemType.CONTACT, contact.getFlagBitmask(), new String[] { tag.getId() }, true);
    params.setZimbraFetchMode(ZimbraFetchMode.MODSEQ);
    results = zmbox.searchImap(null, params);
    verifyImapSearchResults(results, contactId, -1, contact.getParentId(), contact.getModifiedSequence(), MailItemType.CONTACT, contact.getFlagBitmask(), new String[] { tag.getId() }, true);
    params.setZimbraFetchMode(ZimbraFetchMode.IDS);
    results = zmbox.searchImap(null, params);
    verifyImapSearchResults(results, contactId, -1, -1, -1, null, -1, null, false);
}
Also used : ZimbraQueryHitResults(com.zimbra.common.mailbox.ZimbraQueryHitResults) ZMailbox(com.zimbra.client.ZMailbox) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZMailbox(com.zimbra.client.ZMailbox) ZSearchParams(com.zimbra.client.ZSearchParams) ZTag(com.zimbra.client.ZTag) ZFolder(com.zimbra.client.ZFolder) ZMountpoint(com.zimbra.client.ZMountpoint) ZContact(com.zimbra.client.ZContact) Contact(com.zimbra.cs.mailbox.Contact) Test(org.junit.Test)

Example 4 with ZimbraQueryHitResults

use of com.zimbra.common.mailbox.ZimbraQueryHitResults in project zm-mailbox by Zimbra.

the class ImapHandler method search.

private boolean search(String tag, String command, ImapSearch i4search, boolean byUID, Integer options, List<SortBy> order) throws IOException, ImapException {
    if (!checkState(tag, State.SELECTED)) {
        return true;
    }
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    boolean requiresMODSEQ = i4search.requiresMODSEQ();
    if (requiresMODSEQ) {
        activateExtension(ImapExtension.CONDSTORE);
    }
    // MUST reject any such command with the tagged BAD response."
    if (requiresMODSEQ && !sessionActivated(ImapExtension.CONDSTORE)) {
        throw new ImapParseException(tag, "NOMODSEQ", "cannot SEARCH MODSEQ in this mailbox", true);
    }
    // only supporting one level of sorting sort at this point
    SortBy sort = SortBy.NONE;
    if (order != null && !order.isEmpty()) {
        for (SortBy level : order) {
            if ((sort = level) != SortBy.NONE) {
                break;
            }
        }
    }
    boolean saveResults = (options != null && (options & RETURN_SAVE) != 0);
    boolean unsorted = sort == SortBy.NONE;
    Collection<ImapMessage> hits;
    int modseq = 0;
    try {
        MailboxStore mboxStore = i4folder.getMailbox();
        // TODO any way this can be optimized for non-Mailbox MailboxStore?
        if (unsorted && (mboxStore instanceof Mailbox) && i4search.canBeRunLocally()) {
            mboxStore.lock(false);
            try {
                hits = i4search.evaluate(i4folder);
                hits.remove(null);
            } finally {
                mboxStore.unlock();
            }
        } else {
            hits = unsorted ? new ImapMessageSet() : new ArrayList<ImapMessage>();
            try (ZimbraQueryHitResults zqr = runSearch(i4search, i4folder, sort, requiresMODSEQ ? SearchParams.Fetch.MODSEQ : SearchParams.Fetch.IDS)) {
                for (ZimbraQueryHit hit = zqr.getNext(); hit != null; hit = zqr.getNext()) {
                    ImapMessage i4msg = i4folder.getById(hit.getItemId());
                    if (i4msg == null || i4msg.isExpunged()) {
                        continue;
                    }
                    hits.add(i4msg);
                    if (requiresMODSEQ)
                        modseq = Math.max(modseq, hit.getModifiedSequence());
                }
            }
        }
    } catch (ServiceException e) {
        // variable to the empty sequence."
        if (saveResults) {
            i4folder.saveSearchResults(new ImapMessageSet());
        }
        ZimbraLog.imap.warn("%s failed", command, e);
        sendNO(tag, command + " failed");
        return true;
    }
    int size = hits.size();
    ImapMessage first = null;
    ImapMessage last = null;
    if (size != 0 && options != null && (options & (RETURN_MIN | RETURN_MAX)) != 0) {
        if (unsorted) {
            first = ((ImapMessageSet) hits).first();
            last = ((ImapMessageSet) hits).last();
        } else {
            first = ((List<ImapMessage>) hits).get(0);
            last = ((List<ImapMessage>) hits).get(size - 1);
        }
    }
    StringBuilder result = null;
    if (options == null) {
        result = new StringBuilder(command);
        for (ImapMessage i4msg : hits) {
            result.append(' ').append(getMessageId(i4msg, byUID));
        }
    } else if (options != RETURN_SAVE) {
        // Note: rfc5267's ESORT reuses the ESEARCH response i.e. response result starts with "ESEARCH" NOT "ESORT"
        // This is slightly inconsistent as rfc5256's SORT response result starts with "SORT"...
        result = new StringBuilder("ESEARCH (TAG \"").append(tag).append("\")");
        if (byUID) {
            result.append(" UID");
        }
        if (first != null && (options & RETURN_MIN) != 0) {
            result.append(" MIN ").append(getMessageId(first, byUID));
        }
        if (last != null && (options & RETURN_MAX) != 0) {
            result.append(" MAX ").append(getMessageId(last, byUID));
        }
        if ((options & RETURN_COUNT) != 0) {
            result.append(" COUNT ").append(size);
        }
        if (size != 0 && (options & RETURN_ALL) != 0) {
            result.append(" ALL ").append(ImapFolder.encodeSubsequence(hits, byUID));
        }
    }
    if (modseq > 0 && result != null) {
        result.append(" (MODSEQ ").append(modseq).append(')');
    }
    if (saveResults) {
        if (size == 0 || options == RETURN_SAVE || (options & (RETURN_COUNT | RETURN_ALL)) != 0) {
            i4folder.saveSearchResults(unsorted ? (ImapMessageSet) hits : new ImapMessageSet(hits));
        } else {
            ImapMessageSet saved = new ImapMessageSet();
            if (first != null && (options & RETURN_MIN) != 0) {
                saved.add(first);
            }
            if (last != null && (options & RETURN_MAX) != 0) {
                saved.add(last);
            }
            i4folder.saveSearchResults(saved);
        }
    }
    if (result != null) {
        sendUntagged(result.toString());
    }
    sendNotifications(byUID, false);
    sendOK(tag, (byUID ? "UID " : "") + command + " completed");
    return true;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) SortBy(com.zimbra.cs.index.SortBy) ZimbraQueryHit(com.zimbra.common.mailbox.ZimbraQueryHit) ArrayList(java.util.ArrayList) ZimbraQueryHitResults(com.zimbra.common.mailbox.ZimbraQueryHitResults) Mailbox(com.zimbra.cs.mailbox.Mailbox) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) ImapMessageSet(com.zimbra.cs.imap.ImapMessage.ImapMessageSet)

Example 5 with ZimbraQueryHitResults

use of com.zimbra.common.mailbox.ZimbraQueryHitResults in project zm-mailbox by Zimbra.

the class ImapSessionManager method loadVirtualFolder.

/**
 * Fetches the messages contained within a search folder.  When a search folder is IMAP-visible, it appears in
 * folder listings, is SELECTable READ-ONLY, and appears to have all matching messages as its contents.
 * If it is not visible, it will be completely hidden from all IMAP commands.
 * @param octxt   Encapsulation of the authenticated user.
 * @param search  The search folder being exposed.
 */
private static List<ImapMessage> loadVirtualFolder(OperationContext octxt, SearchFolderStore search) throws ServiceException {
    List<ImapMessage> i4list = Lists.newArrayList();
    Set<MailItemType> types = ImapFolder.getMailItemTypeConstraint(search);
    if (types.isEmpty()) {
        return i4list;
    }
    MailboxStore mbox = search.getMailboxStore();
    ZimbraSearchParams params = mbox.createSearchParams(search.getQuery());
    params.setIncludeTagDeleted(true);
    params.setMailItemTypes(types);
    params.setZimbraSortBy(ZimbraSortBy.dateAsc);
    params.setLimit(1000);
    params.setZimbraFetchMode(ZimbraFetchMode.IMAP);
    try {
        ZimbraQueryHitResults zqr = mbox.searchImap(octxt, params);
        try {
            for (ZimbraQueryHit hit = zqr.getNext(); hit != null; hit = zqr.getNext()) {
                i4list.add(new ImapMessage(hit));
            }
        } finally {
            zqr.close();
        }
    } catch (ServiceException e) {
        throw e;
    } catch (Exception e) {
        throw ServiceException.FAILURE("failure opening search folder", e);
    }
    return i4list;
}
Also used : ZimbraQueryHitResults(com.zimbra.common.mailbox.ZimbraQueryHitResults) MailboxStore(com.zimbra.common.mailbox.MailboxStore) ZimbraSearchParams(com.zimbra.common.mailbox.ZimbraSearchParams) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) ZimbraQueryHit(com.zimbra.common.mailbox.ZimbraQueryHit) MailItemType(com.zimbra.common.mailbox.MailItemType) ServiceException(com.zimbra.common.service.ServiceException) MailboxInMaintenanceException(com.zimbra.cs.mailbox.MailServiceException.MailboxInMaintenanceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException)

Aggregations

ZimbraQueryHitResults (com.zimbra.common.mailbox.ZimbraQueryHitResults)6 ZimbraQueryHit (com.zimbra.common.mailbox.ZimbraQueryHit)4 ServiceException (com.zimbra.common.service.ServiceException)4 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)4 Mailbox (com.zimbra.cs.mailbox.Mailbox)4 ZMailbox (com.zimbra.client.ZMailbox)3 ZMountpoint (com.zimbra.client.ZMountpoint)3 Test (org.junit.Test)3 ZSearchParams (com.zimbra.client.ZSearchParams)2 ZTag (com.zimbra.client.ZTag)2 MailboxStore (com.zimbra.common.mailbox.MailboxStore)2 ZimbraSearchParams (com.zimbra.common.mailbox.ZimbraSearchParams)2 AccountServiceException (com.zimbra.cs.account.AccountServiceException)2 ArrayList (java.util.ArrayList)2 ZContact (com.zimbra.client.ZContact)1 ZFolder (com.zimbra.client.ZFolder)1 ZOutgoingMessage (com.zimbra.client.ZMailbox.ZOutgoingMessage)1 ZMessage (com.zimbra.client.ZMessage)1 MailItemType (com.zimbra.common.mailbox.MailItemType)1 SoapFaultException (com.zimbra.common.soap.SoapFaultException)1