Search in sources :

Example 21 with MailboxStore

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

the class ImapHandler method expungeMessages.

private boolean expungeMessages(String tag, ImapFolder i4folder, String sequenceSet) throws ServiceException, IOException, ImapParseException {
    Set<ImapMessage> i4set;
    synchronized (i4folder.getMailbox()) {
        i4set = sequenceSet == null ? null : i4folder.getSubsequence(tag, sequenceSet, true);
    }
    List<Integer> ids = new ArrayList<Integer>(SUGGESTED_DELETE_BATCH_SIZE);
    boolean changed = false;
    long checkpoint = System.currentTimeMillis();
    MailboxStore selectedMailbox = selectedFolderListener.getMailbox();
    for (int i = 1, max = i4folder.getSize(); i <= max; i++) {
        ImapMessage i4msg = i4folder.getBySequence(i);
        if ((i4msg != null && !i4msg.isExpunged() && (i4msg.flags & Flag.BITMASK_DELETED) > 0) && (i4set == null || i4set.contains(i4msg))) {
            ids.add(i4msg.msgId);
            changed = true;
        }
        if (ids.size() >= (i == max ? 1 : SUGGESTED_DELETE_BATCH_SIZE)) {
            List<Integer> nonExistingItems = new ArrayList<Integer>();
            ZimbraLog.imap.debug("  ** deleting: %s", ids);
            selectedMailbox.delete(getContext(), ids, nonExistingItems);
            ids.clear();
            for (Integer itemId : nonExistingItems) {
                i4msg = i4folder.getById(itemId);
                if (i4msg != null) {
                    i4msg.setExpunged(true);
                }
            }
            nonExistingItems.clear();
            // 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;
            }
        }
    }
    if (changed) {
        selectedMailbox.resetRecentMessageCount(getContext());
    }
    return changed;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) ArrayList(java.util.ArrayList)

Example 22 with MailboxStore

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

the class ImapListener method reload.

protected ImapFolder reload() throws ImapSessionClosedException {
    // ZESC-460, ZCS-4004: Ensure mailbox was not modified by another thread
    MailboxStore mbox = mailbox;
    if (mbox == null) {
        throw new ImapSessionClosedException();
    }
    // Mailbox.endTransaction() -> ImapSession.notifyPendingChanges() locks in the order of Mailbox -> ImapSession.
    // Need to lock in the same order here, otherwise can result in deadlock.
    // PagedFolderData.replay() locks Mailbox deep inside of it.
    mbox.lock(true);
    try {
        synchronized (this) {
            // if the data's already paged in, we can short-circuit
            if (mFolder instanceof PagedFolderData) {
                PagedFolderData paged = (PagedFolderData) mFolder;
                ImapFolder i4folder = MANAGER.deserialize(paged.getCacheKey());
                if (i4folder == null) {
                    // cache miss
                    if (ImapSessionManager.isActiveKey(paged.getCacheKey())) {
                        ZimbraLog.imap.debug("cache miss in active cache with key %s. %s", paged.getCacheKey(), this);
                    }
                    return null;
                }
                try {
                    paged.restore(i4folder);
                } catch (ServiceException e) {
                    ZimbraLog.imap.warn("Failed to restore folder %s for session %s", paged.getCacheKey(), this, e);
                    return null;
                }
                // need to switch target before replay (yes, this is inelegant)
                mFolder = i4folder;
                // replay all queued events into the restored folder
                try {
                    // catch some error and return null so we drop cache and reload from db
                    paged.replay();
                    if (hasFailedRenumber()) {
                        return handleRenumberError(paged.getCacheKey());
                    }
                } catch (ImapRenumberException e) {
                    return handleRenumberError(paged.getCacheKey());
                }
                // if it's a disconnected session, no need to track expunges
                if (!isInteractive()) {
                    i4folder.collapseExpunged(false);
                }
            }
            return (ImapFolder) mFolder;
        }
    } finally {
        mbox.unlock();
    }
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) ServiceException(com.zimbra.common.service.ServiceException)

Example 23 with MailboxStore

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

the class ImapListener method updateAccessTime.

@Override
public void updateAccessTime() {
    super.updateAccessTime();
    // ZESC-460, ZCS-4004: Ensure mailbox was not modified by another thread
    MailboxStore mbox = mailbox;
    if (mbox == null) {
        return;
    }
    mbox.lock(true);
    try {
        synchronized (this) {
            PagedFolderData paged = mFolder instanceof PagedFolderData ? (PagedFolderData) mFolder : null;
            if (paged != null) {
                // if the data's already paged in, we can short-circuit
                MANAGER.updateAccessTime(paged.getCacheKey());
            }
        }
    } finally {
        mbox.unlock();
    }
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore)

Example 24 with MailboxStore

use of com.zimbra.common.mailbox.MailboxStore 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 25 with MailboxStore

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

the class ImapHandler method doNOOP.

private boolean doNOOP(String tag) throws IOException {
    ImapListener i4selected = getCurrentImapListener();
    if (i4selected != null) {
        MailboxStore mbox = i4selected.getMailbox();
        if (mbox != null) {
            try {
                mbox.noOp();
            } catch (ServiceException e) {
                ZimbraLog.imap.error("NOOP failed with error %s", e.getMessage(), e);
                sendNO(tag, "NOOP failed");
                return canContinue(e);
            }
        }
    }
    sendNotifications(true, false);
    sendOK(tag, "NOOP completed");
    return true;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException)

Aggregations

MailboxStore (com.zimbra.common.mailbox.MailboxStore)34 ServiceException (com.zimbra.common.service.ServiceException)22 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)17 AccountServiceException (com.zimbra.cs.account.AccountServiceException)14 SearchFolderStore (com.zimbra.common.mailbox.SearchFolderStore)10 FolderStore (com.zimbra.common.mailbox.FolderStore)9 ArrayList (java.util.ArrayList)6 ItemIdentifier (com.zimbra.common.mailbox.ItemIdentifier)5 Account (com.zimbra.cs.account.Account)4 ZimbraMailItem (com.zimbra.common.mailbox.ZimbraMailItem)3 ImapMessageSet (com.zimbra.cs.imap.ImapMessage.ImapMessageSet)3 Mailbox (com.zimbra.cs.mailbox.Mailbox)3 IOException (java.io.IOException)3 ZMailbox (com.zimbra.client.ZMailbox)2 ZSharedFolder (com.zimbra.client.ZSharedFolder)2 MountpointStore (com.zimbra.common.mailbox.MountpointStore)2 ZimbraQueryHit (com.zimbra.common.mailbox.ZimbraQueryHit)2 ZimbraQueryHitResults (com.zimbra.common.mailbox.ZimbraQueryHitResults)2 ZimbraSearchParams (com.zimbra.common.mailbox.ZimbraSearchParams)2 GuestAccount (com.zimbra.cs.account.GuestAccount)2