Search in sources :

Example 1 with ImapMessageSet

use of com.zimbra.cs.imap.ImapMessage.ImapMessageSet in project zm-mailbox by Zimbra.

the class ImapFolder method getSubsequence.

/**
 * {@code allowOutOfRangeMsgSeq} introduced for Bug 27855 to workaround iPhone IMAP client bug where
 * it used to(?) include out of range message sequence numbers in SEARCH requests. Also used when fetching
 * flag information as part of SELECT/EXAMINE with QRESYNC
 */
protected ImapMessageSet getSubsequence(String tag, String subseqStr, boolean byUID, boolean allowOutOfRangeMsgSeq, boolean includeExpunged) throws ImapParseException {
    ImapMessageSet result = new ImapMessageSet();
    if (subseqStr == null || subseqStr.trim().isEmpty()) {
        return result;
    } else if ("$".equals(subseqStr)) {
        return getSavedSearchResults();
    }
    for (Pair<Integer, Integer> range : normalizeSubsequence(subseqStr, byUID)) {
        int lower = range.getFirst();
        int upper = range.getSecond();
        if (!byUID && !allowOutOfRangeMsgSeq && ((lower < 1) || upper > getSize())) {
            // includes "*" if the selected mailbox is empty."
            throw new ImapParseException(tag, "invalid message sequence number: " + subseqStr);
        } else if (lower == upper) {
            // single message -- get it and add it (may be null)
            result.add(byUID ? getByImapId(lower) : getBySequence(lower, includeExpunged));
        } else {
            // range of messages -- get them and add them (may be null)
            if (!byUID) {
                upper = Math.min(getSize(), upper);
                for (int seq = Math.max(0, lower); seq <= upper; seq++) {
                    result.add(getBySequence(seq, includeExpunged));
                }
            } else {
                ImapMessage i4msg;
                int start = uidSearch(lower);
                int end = uidSearch(upper);
                if (start < 0) {
                    start = -start - 1;
                }
                if (end < 0) {
                    end = -end - 2;
                }
                for (int seq = start; seq <= end; seq++) {
                    if ((i4msg = getBySequence(seq + 1)) != null) {
                        result.add(i4msg);
                    }
                }
            }
        }
    }
    return result;
}
Also used : ImapMessageSet(com.zimbra.cs.imap.ImapMessage.ImapMessageSet)

Example 2 with ImapMessageSet

use of com.zimbra.cs.imap.ImapMessage.ImapMessageSet 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 3 with ImapMessageSet

use of com.zimbra.cs.imap.ImapMessage.ImapMessageSet in project zm-mailbox by Zimbra.

the class ImapHandler method doSTORE.

private boolean doSTORE(String tag, String sequenceSet, List<String> flagNames, StoreAction operation, boolean silent, int modseq, boolean byUID) throws IOException, ImapException {
    checkCommandThrottle(new StoreCommand(sequenceSet, flagNames, operation, modseq));
    if (!checkState(tag, State.SELECTED)) {
        return true;
    }
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    if (!i4folder.isWritable()) {
        sendNO(tag, "mailbox selected READ-ONLY");
        return true;
    }
    if (modseq >= 0) {
        activateExtension(ImapExtension.CONDSTORE);
    }
    boolean modseqEnabled = sessionActivated(ImapExtension.CONDSTORE);
    // MUST reject any such command with the tagged BAD response."
    if (!modseqEnabled && modseq >= 0) {
        throw new ImapParseException(tag, "NOMODSEQ", "cannot STORE UNCHANGEDSINCE in this mailbox", true);
    }
    ImapMessageSet modifyConflicts = modseqEnabled ? new ImapMessageSet() : null;
    String command = (byUID ? "UID STORE" : "STORE");
    List<Tag> newTags = (operation != StoreAction.REMOVE ? new ArrayList<Tag>() : null);
    MailboxStore mbox = selectedFolderListener.getMailbox();
    Set<ImapMessage> i4set;
    mbox.lock(true);
    try {
        i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
    } finally {
        mbox.unlock();
    }
    boolean allPresent = byUID || !i4set.contains(null);
    i4set.remove(null);
    try {
        // list of tag names (not including Flags)
        List<String> tags = Lists.newArrayList();
        // just Flag objects, no need to convert Tag objects to ImapFlag here
        Set<ImapFlag> i4flags = new HashSet<ImapFlag>(flagNames.size());
        for (String name : flagNames) {
            ImapFlag i4flag = i4folder.getFlagByName(name);
            if (i4flag == null) {
                tags.add(name);
                // new tag for this folder
                continue;
            } else if (i4flag.mId > 0) {
                tags.add(i4flag.mName);
            } else {
                i4flags.add(i4flag);
            }
            if (operation != StoreAction.REMOVE) {
                if (i4flag.mId == Flag.ID_DELETED) {
                    if (!i4folder.getPath().isWritable(ACL.RIGHT_DELETE)) {
                        throw ServiceException.PERM_DENIED("you do not have permission to set the \\Deleted flag");
                    }
                } else if (i4flag.mPermanent && (!i4folder.getPath().isWritable(ACL.RIGHT_WRITE))) {
                    throw ServiceException.PERM_DENIED("you do not have permission to set the " + i4flag.mName + " flag");
                }
            }
        }
        // if we're doing a STORE FLAGS (i.e. replace), precompute the new set of flags for all the affected messages
        int flags = Flag.BITMASK_UNREAD;
        short sflags = 0;
        if (operation == StoreAction.REPLACE) {
            for (ImapFlag i4flag : i4flags) {
                if (!i4flag.mPermanent) {
                    sflags = (byte) (i4flag.mPositive ? sflags | i4flag.mBitmask : sflags & ~i4flag.mBitmask);
                } else {
                    flags = (int) (i4flag.mPositive ? flags | i4flag.mBitmask : flags & ~i4flag.mBitmask);
                }
            }
        }
        long checkpoint = System.currentTimeMillis();
        int i = 0;
        List<ImapMessage> i4list = new ArrayList<ImapMessage>(SUGGESTED_BATCH_SIZE);
        List<Integer> idlist = new ArrayList<Integer>(SUGGESTED_BATCH_SIZE);
        for (ImapMessage msg : i4set) {
            // we're sending 'em off in batches of 100
            i4list.add(msg);
            idlist.add(msg.msgId);
            if (++i % SUGGESTED_BATCH_SIZE != 0 && i != i4set.size()) {
                continue;
            }
            mbox.lock(true);
            try {
                String folderOwner = i4folder.getFolder().getFolderItemIdentifier().accountId;
                List<ItemIdentifier> itemIds = ItemIdentifier.fromAccountIdAndItemIds((folderOwner != null) ? folderOwner : mbox.getAccountId(), idlist);
                if (modseq >= 0) {
                    List<ZimbraMailItem> items = mbox.getItemsById(getContext(), itemIds);
                    for (int idx = items.size() - 1; idx >= 0; idx--) {
                        ImapMessage i4msg = i4list.get(idx);
                        if (items.get(idx).getModifiedSequence() > modseq) {
                            modifyConflicts.add(i4msg);
                            i4list.remove(idx);
                            idlist.remove(idx);
                            allPresent = false;
                        }
                    }
                }
                try {
                    // if it was a STORE [+-]?FLAGS.SILENT, temporarily disable notifications
                    if (silent && !modseqEnabled) {
                        i4folder.disableNotifications();
                    }
                    if (operation == StoreAction.REPLACE) {
                        // replace real tags and flags on all messages
                        mbox.setTags(getContext(), itemIds, flags, tags);
                        // replace session tags on all messages
                        for (ImapMessage i4msg : i4list) {
                            i4msg.setSessionFlags(sflags, i4folder);
                        }
                    } else {
                        for (ImapFlag i4flag : i4flags) {
                            boolean add = operation == StoreAction.ADD ^ !i4flag.mPositive;
                            if (i4flag.mPermanent) {
                                // real Flag (not a Tag); do a batch update to the DB
                                if ((i4flag.mBitmask & Flag.BITMASK_DELETED) > 0) {
                                    ZimbraLog.imap.info("IMAP client has flagged the item with id %d to be Deleted altertag", msg.msgId);
                                }
                                mbox.alterTag(getContext(), itemIds, i4flag.mName, add);
                            } else {
                                // session tag; update one-by-one in memory only
                                for (ImapMessage i4msg : i4list) {
                                    i4msg.setSessionFlags((short) (add ? i4msg.sflags | i4flag.mBitmask : i4msg.sflags & ~i4flag.mBitmask), i4folder);
                                }
                            }
                        }
                        boolean add = operation == StoreAction.ADD;
                        // add (or remove) Tags
                        for (String tagName : tags) {
                            mbox.alterTag(getContext(), itemIds, tagName, add);
                        }
                    }
                } finally {
                    // if it was a STORE [+-]?FLAGS.SILENT, reenable notifications
                    i4folder.enableNotifications();
                }
            } finally {
                mbox.unlock();
            }
            if (!silent || modseqEnabled) {
                for (ImapMessage i4msg : i4list) {
                    ImapFolder.DirtyMessage dirty = i4folder.undirtyMessage(i4msg);
                    if (silent && (dirty == null || dirty.modseq <= 0)) {
                        continue;
                    }
                    StringBuilder ntfn = new StringBuilder();
                    boolean empty = true;
                    ntfn.append(i4msg.sequence).append(" FETCH (");
                    if (!silent) {
                        ntfn.append(i4msg.getFlags(i4folder));
                        empty = false;
                    }
                    // caused by a UID command..."
                    if (byUID) {
                        ntfn.append(empty ? "" : " ").append("UID ").append(i4msg.imapUid);
                        empty = false;
                    }
                    if (dirty != null && dirty.modseq > 0 && modseqEnabled) {
                        ntfn.append(empty ? "" : " ").append("MODSEQ (").append(dirty.modseq).append(')');
                        empty = false;
                    }
                    sendUntagged(ntfn.append(')').toString());
                }
            } else {
                // send a gratuitous untagged response to keep pissy clients from closing the socket from inactivity
                long now = System.currentTimeMillis();
                if (now - checkpoint > MAXIMUM_IDLE_PROCESSING_MILLIS) {
                    sendIdleUntagged();
                    checkpoint = now;
                }
            }
            i4list.clear();
            idlist.clear();
        }
    } catch (ServiceException e) {
        deleteTags(newTags);
        if (e.getCode().equals(MailServiceException.INVALID_NAME)) {
            ZimbraLog.imap.info("%s failed: %s", command, e.getMessage());
        } else {
            ZimbraLog.imap.warn("%s failed", command, e);
        }
        sendNO(tag, command + " failed");
        return canContinue(e);
    }
    boolean hadConflicts = modifyConflicts != null && !modifyConflicts.isEmpty();
    String conflicts = hadConflicts ? " [MODIFIED " + ImapFolder.encodeSubsequence(modifyConflicts, byUID) + ']' : "";
    sendNotifications(byUID, false);
    // a FETCH response for the non-expunged messages along with a tagged NO."
    if (silent || allPresent) {
        sendOK(tag, command + conflicts + " completed");
    } else {
        sendNO(tag, command + conflicts + " completed");
    }
    return true;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) ArrayList(java.util.ArrayList) ItemIdentifier(com.zimbra.common.mailbox.ItemIdentifier) ZimbraMailItem(com.zimbra.common.mailbox.ZimbraMailItem) ImapMessageSet(com.zimbra.cs.imap.ImapMessage.ImapMessageSet) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet) ImapFlag(com.zimbra.cs.imap.ImapFlagCache.ImapFlag) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) Tag(com.zimbra.cs.mailbox.Tag)

Example 4 with ImapMessageSet

use of com.zimbra.cs.imap.ImapMessage.ImapMessageSet in project zm-mailbox by Zimbra.

the class ImapHandler method fetch.

private boolean fetch(String tag, String sequenceSet, int attributes, List<ImapPartSpecifier> parts, boolean byUID, int changedSince, boolean standalone, boolean allowOutOfRangeMsgSeq) throws IOException, ImapException {
    if (!checkState(tag, State.SELECTED)) {
        return true;
    }
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    // of whether a UID was specified as a message data item to the FETCH."
    if (byUID) {
        attributes |= FETCH_UID;
    }
    String command = (byUID ? "UID FETCH" : "FETCH");
    boolean markRead = i4folder.isWritable() && (attributes & FETCH_MARK_READ) != 0;
    // the CHANGEDSINCE UID FETCH modifier."
    if ((attributes & FETCH_VANISHED) != 0 && (!byUID || changedSince < 0)) {
        throw new ImapParseException(tag, "cannot specify VANISHED without CHANGEDSINCE");
    }
    if (changedSince >= 0) {
        attributes |= FETCH_MODSEQ;
    }
    if ((attributes & FETCH_MODSEQ) != 0) {
        activateExtension(ImapExtension.CONDSTORE);
    }
    boolean modseqEnabled = sessionActivated(ImapExtension.CONDSTORE);
    // MUST reject any such command with the tagged BAD response."
    if (!modseqEnabled && (attributes & FETCH_MODSEQ) != 0) {
        throw new ImapParseException(tag, "NOMODSEQ", "cannot FETCH MODSEQ in this mailbox", true);
    }
    List<ImapPartSpecifier> fullMessage = new ArrayList<ImapPartSpecifier>();
    if (parts != null && !parts.isEmpty()) {
        for (Iterator<ImapPartSpecifier> it = parts.iterator(); it.hasNext(); ) {
            ImapPartSpecifier pspec = it.next();
            if (pspec.isEntireMessage()) {
                it.remove();
                fullMessage.add(pspec);
            }
        }
    }
    ImapMessageSet i4set;
    MailboxStore mbox = i4folder.getMailbox();
    mbox.lock(false);
    try {
        i4set = i4folder.getSubsequence(tag, sequenceSet, byUID, allowOutOfRangeMsgSeq, true);
        i4set.remove(null);
    } finally {
        mbox.unlock();
    }
    // if VANISHED was requested, we need to return the set of UIDs that *don't* exist in the folder
    if (byUID && (attributes & FETCH_VANISHED) != 0) {
        int highwater = Integer.MAX_VALUE;
        try {
            highwater = i4folder.getCurrentMODSEQ();
        } catch (ServiceException e) {
        }
        if (highwater > changedSince) {
            String vanished = i4folder.invertSubsequence(sequenceSet, true, i4set);
            if (!vanished.isEmpty()) {
                sendUntagged("VANISHED (EARLIER) " + vanished);
            }
        }
    }
    // make sure it's not just a set of nothing but expunged messages
    if (!byUID && !i4set.isEmpty()) {
        boolean nonePresent = true;
        for (ImapMessage i4msg : i4set) {
            if (!i4msg.isExpunged()) {
                nonePresent = false;
                break;
            }
        }
        if (nonePresent) {
            // expunged, the server SHOULD return only a tagged NO."
            if (standalone) {
                sendNO(tag, "all of the requested messages have been expunged");
            }
            return true;
        }
    }
    // if a CHANGEDSINCE sequence number was specified, narrow the message set before iterating over the messages
    if (changedSince >= 0) {
        try {
            // get a list of all the messages modified since the checkpoint
            ImapMessageSet modified = new ImapMessageSet();
            for (int id : mbox.getIdsOfModifiedItemsInFolder(getContext(), changedSince, i4folder.getId())) {
                ImapMessage i4msg = i4folder.getById(id);
                if (i4msg != null) {
                    modified.add(i4msg);
                }
            }
            // and intersect those "modified" messages with the set of requested messages
            i4set.retainAll(modified);
        } catch (ServiceException e) {
            if (standalone) {
                ZimbraLog.imap.warn(command + " failed", e);
                sendNO(tag, command + " failed");
                return canContinue(e);
            }
        }
    }
    mbox.lock(true);
    try {
        if (i4folder.areTagsDirty()) {
            sendUntagged("FLAGS (" + StringUtil.join(" ", i4folder.getFlagList(false)) + ')');
            i4folder.setTagsDirty(false);
        }
    } finally {
        mbox.unlock();
    }
    ReentrantLock lock = null;
    try {
        for (ImapMessage i4msg : i4set) {
            PrintStream result = new PrintStream(output, false, Charsets.UTF_8.name());
            try {
                result.print("* " + i4msg.sequence + " FETCH (");
                if (i4msg.isExpunged()) {
                    fetchStub(i4msg, i4folder, attributes, parts, fullMessage, result);
                    continue;
                }
                boolean markMessage = markRead && (i4msg.flags & Flag.BITMASK_UNREAD) != 0;
                boolean empty = true;
                ZimbraMailItem item = null;
                MimeMessage mm;
                if (!fullMessage.isEmpty() || (parts != null && !parts.isEmpty()) || (attributes & ~FETCH_FROM_CACHE) != 0) {
                    if (lock == null && LC.imap_throttle_fetch.booleanValue()) {
                        lock = commandThrottle.lock(credentials.getAccountId());
                    }
                    try {
                        String folderOwner = i4folder.getFolder().getFolderItemIdentifier().accountId;
                        ItemIdentifier iid = ItemIdentifier.fromAccountIdAndItemId((folderOwner != null) ? folderOwner : mbox.getAccountId(), i4msg.msgId);
                        item = mbox.getItemById(getContext(), iid, i4msg.getType().toCommon());
                    } catch (NoSuchItemException nsie) {
                        // just in case we're out of sync, force this message back into sync
                        i4folder.markMessageExpunged(i4msg);
                        fetchStub(i4msg, i4folder, attributes, parts, fullMessage, result);
                        continue;
                    }
                }
                if ((attributes & FETCH_UID) != 0) {
                    result.print((empty ? "" : " ") + "UID " + i4msg.imapUid);
                    empty = false;
                }
                if ((attributes & FETCH_INTERNALDATE) != 0) {
                    result.print((empty ? "" : " ") + "INTERNALDATE \"" + DateUtil.toImapDateTime(new Date(item.getDate())) + '"');
                    empty = false;
                }
                if ((attributes & FETCH_RFC822_SIZE) != 0) {
                    result.print((empty ? "" : " ") + "RFC822.SIZE " + i4msg.getSize(item));
                    empty = false;
                }
                if ((attributes & FETCH_BINARY_SIZE) != 0) {
                    result.print((empty ? "" : " ") + "BINARY.SIZE[] " + i4msg.getSize(item));
                    empty = false;
                }
                if (!fullMessage.isEmpty()) {
                    for (ImapPartSpecifier pspec : fullMessage) {
                        result.print(empty ? "" : " ");
                        pspec.write(result, output, item);
                        empty = false;
                    }
                }
                if ((parts != null && !parts.isEmpty()) || (attributes & FETCH_FROM_MIME) != 0) {
                    mm = ImapMessage.getMimeMessage(item);
                    if ((attributes & FETCH_BODY) != 0) {
                        result.print(empty ? "" : " ");
                        result.print("BODY ");
                        ImapMessage.serializeStructure(result, mm, false);
                        empty = false;
                    }
                    if ((attributes & FETCH_BODYSTRUCTURE) != 0) {
                        result.print(empty ? "" : " ");
                        result.print("BODYSTRUCTURE ");
                        ImapMessage.serializeStructure(result, mm, true);
                        empty = false;
                    }
                    if ((attributes & FETCH_ENVELOPE) != 0) {
                        result.print(empty ? "" : " ");
                        result.print("ENVELOPE ");
                        ImapMessage.serializeEnvelope(result, mm);
                        empty = false;
                    }
                    if (parts != null) {
                        for (ImapPartSpecifier pspec : parts) {
                            result.print(empty ? "" : " ");
                            pspec.write(result, output, mm);
                            empty = false;
                        }
                    }
                }
                // FIXME: optimize by doing a single mark-read op on multiple messages
                if (markMessage) {
                    String folderOwner = i4folder.getFolder().getFolderItemIdentifier().accountId;
                    ItemIdentifier iid = ItemIdentifier.fromAccountIdAndItemId((folderOwner != null) ? folderOwner : mbox.getAccountId(), i4msg.msgId);
                    mbox.flagItemAsRead(getContext(), iid, i4msg.getMailItemType());
                }
                ImapFolder.DirtyMessage unsolicited = i4folder.undirtyMessage(i4msg);
                if ((attributes & FETCH_FLAGS) != 0 || unsolicited != null) {
                    result.print(empty ? "" : " ");
                    result.print(i4msg.getFlags(i4folder));
                    empty = false;
                }
                // data items in all subsequent unsolicited FETCH responses."
                if ((attributes & FETCH_MODSEQ) != 0 || (modseqEnabled && unsolicited != null)) {
                    int modseq = unsolicited == null ? item.getModifiedSequence() : unsolicited.modseq;
                    result.print((empty ? "" : " ") + "MODSEQ (" + modseq + ')');
                    empty = false;
                }
            } catch (ImapPartSpecifier.BinaryDecodingException e) {
                // don't write this response line if we're returning NO
                result = null;
                throw new ImapParseException(tag, "UNKNOWN-CTE", command + "failed: unknown content-type-encoding", false);
            } catch (SoapFaultException e) {
                fetchException(e);
            } catch (ServiceException e) {
                Throwable cause = e.getCause();
                if (cause instanceof IOException) {
                    fetchException(cause);
                } else {
                    ZimbraLog.imap.warn("ignoring error during " + command + ": ", e);
                    continue;
                }
            } catch (MessagingException e) {
                ZimbraLog.imap.warn("ignoring error during " + command + ": ", e);
                continue;
            } catch (IOException ioe) {
                fetchException(ioe);
            } finally {
                if (result != null) {
                    result.write(')');
                    output.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);
                    output.flush();
                }
            }
        }
    } finally {
        if (lock != null) {
            lock.unlock();
        }
    }
    if (standalone) {
        sendNotifications(byUID, false);
        sendOK(tag, command + " completed");
    }
    return true;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) ArrayList(java.util.ArrayList) ItemIdentifier(com.zimbra.common.mailbox.ItemIdentifier) MimeMessage(javax.mail.internet.MimeMessage) ZimbraMailItem(com.zimbra.common.mailbox.ZimbraMailItem) ImapMessageSet(com.zimbra.cs.imap.ImapMessage.ImapMessageSet) ReentrantLock(java.util.concurrent.locks.ReentrantLock) PrintStream(java.io.PrintStream) MessagingException(javax.mail.MessagingException) IOException(java.io.IOException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) Date(java.util.Date) SoapFaultException(com.zimbra.common.soap.SoapFaultException) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException)

Example 5 with ImapMessageSet

use of com.zimbra.cs.imap.ImapMessage.ImapMessageSet in project zm-mailbox by Zimbra.

the class ImapFolder method getAllMessages.

protected synchronized ImapMessageSet getAllMessages() {
    ImapMessageSet result = new ImapMessageSet();
    if (getSize() > 0) {
        result.addAll(sequence);
        result.remove(null);
    }
    return result;
}
Also used : ImapMessageSet(com.zimbra.cs.imap.ImapMessage.ImapMessageSet)

Aggregations

ImapMessageSet (com.zimbra.cs.imap.ImapMessage.ImapMessageSet)5 MailboxStore (com.zimbra.common.mailbox.MailboxStore)3 ServiceException (com.zimbra.common.service.ServiceException)3 AccountServiceException (com.zimbra.cs.account.AccountServiceException)3 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)3 ArrayList (java.util.ArrayList)3 ItemIdentifier (com.zimbra.common.mailbox.ItemIdentifier)2 ZimbraMailItem (com.zimbra.common.mailbox.ZimbraMailItem)2 ZimbraQueryHit (com.zimbra.common.mailbox.ZimbraQueryHit)1 ZimbraQueryHitResults (com.zimbra.common.mailbox.ZimbraQueryHitResults)1 SoapFaultException (com.zimbra.common.soap.SoapFaultException)1 ImapFlag (com.zimbra.cs.imap.ImapFlagCache.ImapFlag)1 SortBy (com.zimbra.cs.index.SortBy)1 NoSuchItemException (com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException)1 Mailbox (com.zimbra.cs.mailbox.Mailbox)1 Tag (com.zimbra.cs.mailbox.Tag)1 IOException (java.io.IOException)1 PrintStream (java.io.PrintStream)1 Date (java.util.Date)1 HashSet (java.util.HashSet)1