Search in sources :

Example 16 with FolderStore

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

the class ImapHandler method doCOPY.

/**
 * @param path of target folder
 */
protected boolean doCOPY(String tag, String sequenceSet, ImapPath path, boolean byUID) throws IOException, ImapException {
    checkCommandThrottle(new CopyCommand(sequenceSet, path));
    if (!checkState(tag, State.SELECTED)) {
        return true;
    }
    String command = (byUID ? "UID COPY" : "COPY");
    String copyuid = "";
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    MailboxStore mbox = i4folder.getMailbox();
    Set<ImapMessage> i4set;
    mbox.lock(false);
    try {
        i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
    } catch (ImapParseException ipe) {
        ZimbraLog.imap.error(ipe);
        throw ipe;
    } finally {
        mbox.unlock();
    }
    if (i4set.size() > LC.imap_max_items_in_copy.intValue()) {
        sendNO(tag, "COPY rejected, too many items in copy request");
        return true;
    }
    // accessed mailbox that contains expunged messages."
    if (!byUID && i4set.contains(null)) {
        sendNO(tag, "COPY rejected because some of the requested messages were expunged");
        return true;
    }
    i4set.remove(null);
    try {
        if (!path.isVisible()) {
            throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
        } else if (!path.isWritable(ACL.RIGHT_INSERT)) {
            throw ImapServiceException.FOLDER_NOT_WRITABLE(path.asImapPath());
        }
        MailboxStore mbxStore = path.getOwnerMailbox();
        if (null == mbxStore) {
            throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
        }
        FolderStore targetFolder = path.getFolder();
        FolderStore selectedFolder = null;
        try {
            selectedFolder = i4folder.getFolder();
        } catch (ServiceException e1) {
            ZimbraLog.imap.error("Problem with selected folder %s during doCOPY", e1.getMessage());
            return true;
        }
        // check target folder permissions before attempting the copy
        ImapMailboxStore selectedImapMboxStore = i4folder.getImapMailboxStore();
        boolean sameMailbox = selectedImapMboxStore.getAccountId().equalsIgnoreCase(mbxStore.getAccountId());
        boolean selectedFolderInOtherMailbox;
        ItemIdentifier fromFolderId;
        if (selectedFolder instanceof MountpointStore) {
            selectedFolderInOtherMailbox = true;
            fromFolderId = ((MountpointStore) selectedFolder).getTargetItemIdentifier();
        } else if (selectedFolder instanceof ZSharedFolder) {
            selectedFolderInOtherMailbox = true;
            fromFolderId = selectedFolder.getFolderItemIdentifier();
        } else {
            selectedFolderInOtherMailbox = false;
            fromFolderId = selectedFolder.getFolderItemIdentifier();
        }
        int uvv = targetFolder.getUIDValidity();
        ItemId iidTarget = new ItemId(targetFolder, path.getOwnerAccount().getId());
        ItemIdentifier targetIdentifier = iidTarget.toItemIdentifier();
        long checkpoint = System.currentTimeMillis();
        List<Integer> copyUIDs = extensionEnabled("UIDPLUS") ? Lists.newArrayListWithCapacity(i4set.size()) : null;
        final List<ImapMessage> i4list = Lists.newArrayList(i4set);
        final List<List<ImapMessage>> batches = Lists.partition(i4list, SUGGESTED_COPY_BATCH_SIZE);
        for (List<ImapMessage> batch : batches) {
            if (sameMailbox && !selectedFolderInOtherMailbox) {
                copyOwnItems(selectedImapMboxStore, batch, iidTarget, copyUIDs);
            } else {
                copyItemsBetweenMailboxes(selectedImapMboxStore, batch, fromFolderId, targetIdentifier, copyUIDs);
            }
            // 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 (uvv > 0 && copyUIDs != null && copyUIDs.size() > 0) {
            List<Integer> srcUIDs = Lists.newArrayListWithCapacity(i4set.size());
            for (ImapMessage i4msg : i4set) {
                srcUIDs.add(i4msg.imapUid);
            }
            copyuid = "[COPYUID " + uvv + ' ' + ImapFolder.encodeSubsequence(srcUIDs) + ' ' + ImapFolder.encodeSubsequence(copyUIDs) + "] ";
        }
    } catch (IOException e) {
        // 6.4.7: "If the COPY command is unsuccessful for any reason, server implementations
        // MUST restore the destination mailbox to its state before the COPY attempt."
        ZimbraLog.imap.warn("%s failed", command, e);
        sendNO(tag, command + " failed");
        return true;
    } catch (ServiceException e) {
        // 6.4.7: "If the COPY command is unsuccessful for any reason, server implementations
        // MUST restore the destination mailbox to its state before the COPY attempt."
        String rcode = "";
        if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
            ZimbraLog.imap.info("%s failed: no such folder: %s", command, path);
            if (path.isCreatable()) {
                rcode = "[TRYCREATE] ";
            }
        } else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
            ZimbraLog.imap.info("%s failed: folder not visible: %s", command, path);
        } else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_WRITABLE)) {
            ZimbraLog.imap.info("%s failed: folder not writable: %s", command, path);
        } else {
            ZimbraLog.imap.warn("%s failed", command, e);
        }
        sendNO(tag, rcode + command + " failed");
        return canContinue(e);
    }
    // RFC 2180 4.4: "COPY is the only IMAP4 sequence number command that is safe to allow
    // an EXPUNGE response on.  This is because a client is not permitted
    // to cascade several COPY commands together."
    sendNotifications(true, false);
    sendOK(tag, copyuid + command + " completed");
    return true;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore) ZSharedFolder(com.zimbra.client.ZSharedFolder) IOException(java.io.IOException) ItemId(com.zimbra.cs.service.util.ItemId) ItemIdentifier(com.zimbra.common.mailbox.ItemIdentifier) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) MountpointStore(com.zimbra.common.mailbox.MountpointStore) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Example 17 with FolderStore

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

the class ImapHandler method doSUBSCRIBE.

private boolean doSUBSCRIBE(String tag, ImapPath path) throws IOException {
    if (!checkState(tag, State.AUTHENTICATED)) {
        return true;
    }
    try {
        // canonicalizing the path also throws exceptions when the folder doesn't exist
        path.canonicalize();
        if (path.belongsTo(credentials)) {
            if (!path.isVisible()) {
                throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
            }
            FolderStore folder = path.getFolder();
            if (!folder.isIMAPSubscribed()) {
                path.getOwnerMailbox().flagFolderAsSubscribed(getContext(), folder);
            }
        } else {
            credentials.subscribe(path);
        }
    } catch (ServiceException e) {
        if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
            ZimbraLog.imap.info("SUBSCRIBE failed: no such folder: %s", path);
        } else if (e.getCode().equals(ServiceException.PERM_DENIED)) {
            ZimbraLog.imap.info("SUBSCRIBE failed: permission denied on folder: %s", path);
        } else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
            ZimbraLog.imap.info("SUBSCRIBE failed: folder not visible: %s", path);
        } else {
            ZimbraLog.imap.warn("SUBSCRIBE failed", e);
        }
        sendNO(tag, "SUBSCRIBE failed");
        return canContinue(e);
    }
    sendNotifications(true, false);
    sendOK(tag, "SUBSCRIBE completed");
    return true;
}
Also used : AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore)

Example 18 with FolderStore

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

the class ImapSessionManager method openFolder.

protected FolderDetails openFolder(ImapPath path, byte params, ImapHandler handler) throws ServiceException {
    ZimbraLog.imap.debug("opening folder: %s", path);
    if (!path.isSelectable()) {
        throw ServiceException.PERM_DENIED("cannot select folder: " + path);
    }
    if ((params & ImapFolder.SELECT_CONDSTORE) != 0) {
        handler.activateExtension(ImapExtension.CONDSTORE);
    }
    FolderStore folder = path.getFolder();
    String folderIdAsString = folder.getFolderIdAsString();
    int folderId = folder.getFolderIdInOwnerMailbox();
    MailboxStore mbox = folder.getMailboxStore();
    ImapMailboxStore imapStore = ImapMailboxStore.get(mbox);
    // don't have a session when the folder is loaded...
    OperationContext octxt = handler.getCredentials().getContext();
    List<ImapMessage> i4list = null;
    // *always* recalculate the contents of search folders
    if (folder instanceof SearchFolderStore) {
        i4list = loadVirtualFolder(octxt, (SearchFolderStore) folder);
    } else {
        waitForWaitSetNotifications(imapStore, folder);
    }
    mbox.lock(true);
    try {
        // need mInitialRecent to be set *before* loading the folder so we can determine what's \Recent
        if (!(folder instanceof ZSharedFolder)) {
            folder = mbox.getFolderById(octxt, folderIdAsString);
            if (folder == null) {
                throw MailServiceException.NO_SUCH_FOLDER(path.asImapPath());
            }
        }
        int recentCutoff = imapStore.getImapRECENTCutoff(folder);
        if (i4list == null) {
            List<ImapListener> listners = imapStore.getListeners(folder);
            // first option is to duplicate an existing registered session
            // (could try to just activate an inactive session, but this logic is simpler for now)
            i4list = duplicateExistingSession(folderId, listners);
            // no matching session means we next check for serialized folder data
            if (i4list == null) {
                i4list = duplicateSerializedFolder(folder);
            } else if (CONSISTENCY_CHECK) {
                Collections.sort(i4list);
            // sort only if using list from duplicated session which may be out of order
            // if loaded from serialized folder order _should_ already be OK since no changes have occurred
            }
            // do the consistency check, if requested
            if (CONSISTENCY_CHECK) {
                i4list = consistencyCheck(i4list, imapStore, octxt, folder);
            }
            // no matching serialized session means we have to go to the DB to get the messages
            if (i4list == null) {
                ItemIdentifier ident;
                if (folder instanceof MountpointStore) {
                    ident = ((MountpointStore) folder).getTargetItemIdentifier();
                } else {
                    ident = folder.getFolderItemIdentifier();
                }
                i4list = imapStore.openImapFolder(octxt, ident);
            }
        }
        Collections.sort(i4list);
        // check messages for imapUid <= 0 and assign new IMAP IDs if necessary
        renumberMessages(octxt, mbox, i4list);
        ImapFolder i4folder = new ImapFolder(path, params, handler);
        // don't rely on the <code>Folder</code> object being updated in place
        if (!(folder instanceof ZSharedFolder)) {
            folder = mbox.getFolderById(octxt, folderIdAsString);
        }
        // can't set these until *after* loading the folder because UID renumbering affects them
        InitialFolderValues initial = new InitialFolderValues(folder);
        for (ImapMessage i4msg : i4list) {
            i4folder.cache(i4msg, i4msg.imapUid > recentCutoff);
            if (initial.firstUnread == -1 && (i4msg.flags & Flag.BITMASK_UNREAD) != 0) {
                initial.firstUnread = i4msg.sequence;
            }
        }
        i4folder.setInitialSize();
        ZimbraLog.imap.debug("ImapSessionManager.openFolder.  Folder with id=%s added message list %s", folderIdAsString, i4list);
        ImapListener session = null;
        try {
            session = imapStore.createListener(i4folder, handler);
            session.register();
            sessions.put(session, session);
            imapStore.registerWithImapServerListener(session);
            return new FolderDetails(session, initial);
        } catch (ServiceException e) {
            if (session != null) {
                session.unregister();
            }
            throw e;
        }
    } finally {
        mbox.unlock();
    }
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) MailboxStore(com.zimbra.common.mailbox.MailboxStore) FolderStore(com.zimbra.common.mailbox.FolderStore) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) ZSharedFolder(com.zimbra.client.ZSharedFolder) ItemIdentifier(com.zimbra.common.mailbox.ItemIdentifier) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) MountpointStore(com.zimbra.common.mailbox.MountpointStore)

Example 19 with FolderStore

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

the class ImapPath method getReferent.

/**
 * @return If the folder is a mountpoint (i.e. an accepted share), may return an ImapPath representing
 *         that, otherwise, the value is this.
 */
@VisibleForTesting
public ImapPath getReferent() throws ServiceException {
    if (mReferent != null) {
        return mReferent;
    }
    // while calculating, use the base
    mReferent = this;
    // only follow the authenticated user's own mountpoints
    if (mScope == Scope.REFERENCE || mScope == Scope.UNPARSED || !belongsTo(mCredentials)) {
        return mReferent;
    }
    ImapMailboxStore ownerImapMailboxStore = getOwnerImapMailboxStore();
    if (null == ownerImapMailboxStore) {
        return mReferent;
    }
    ItemId iidRemote;
    String subpathRemote = null;
    if (folder == null) {
        try {
            ExistingParentFolderStoreAndUnmatchedPart info = ownerImapMailboxStore.getMailboxStore().getParentFolderStoreAndUnmatchedPart(getContext(), asZimbraPath());
            subpathRemote = info.unmatchedPart;
            if (info.parentFolderStore instanceof MountpointStore || Strings.isNullOrEmpty(subpathRemote)) {
                folder = info.parentFolderStore;
                mItemId = new ItemId(ItemIdentifier.fromOwnerAndFolder(accountIdFromCredentials(), folder));
            }
            if (!(info.parentFolderStore instanceof MountpointStore)) {
                return mReferent;
            }
        } catch (ServiceException e) {
            return mReferent;
        }
    }
    if (!(folder instanceof MountpointStore)) {
        return mReferent;
    }
    // somewhere along the specified path is a visible mountpoint owned by the user
    iidRemote = new ItemId(((MountpointStore) folder).getTargetItemIdentifier());
    // don't allow mountpoints that point at the same mailbox (as it can cause infinite loops)
    if (belongsTo(iidRemote.getAccountId())) {
        return mReferent;
    }
    Account target = Provisioning.getInstance().get(AccountBy.id, iidRemote.getAccountId());
    if (target == null) {
        return mReferent;
    }
    ImapMailboxStore imapMailboxStore = setupMailboxStoreForTarget(target, iidRemote);
    if (null == imapMailboxStore) {
        return mReferent;
    }
    FolderStore fldr = imapMailboxStore.getMailboxStore().getFolderById(getContext(), Integer.toString(iidRemote.getId()));
    if (fldr == null) {
        return mReferent;
    }
    String owner = getOwner(target);
    if (Strings.isNullOrEmpty(subpathRemote)) {
        mReferent = new ImapPath(owner, fldr, mCredentials);
    } else {
        mReferent = ImapPath.get(owner, fldr.getPath() + (fldr.getPath().equals("/") ? "" : "/") + subpathRemote, mCredentials, imapMailboxStore);
    }
    if (mReferent != this) {
        mReferent.mScope = Scope.REFERENCE;
    }
    return mReferent;
}
Also used : Account(com.zimbra.cs.account.Account) ExistingParentFolderStoreAndUnmatchedPart(com.zimbra.common.mailbox.ExistingParentFolderStoreAndUnmatchedPart) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) MountpointStore(com.zimbra.common.mailbox.MountpointStore) FolderStore(com.zimbra.common.mailbox.FolderStore) ItemId(com.zimbra.cs.service.util.ItemId) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 20 with FolderStore

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

the class LocalImapMailboxStore method getVisibleFolders.

@Override
public Collection<FolderStore> getVisibleFolders(OperationContext octxt, ImapCredentials credentials, String owner, ImapPath relativeTo) throws ServiceException {
    Collection<Folder> folders = mailbox.getVisibleFolders(octxt);
    if (folders == null) {
        folders = mailbox.getFolderById(octxt, relativeTo == null ? Mailbox.ID_FOLDER_USER_ROOT : relativeTo.asItemId().getId()).getSubfolderHierarchy();
    }
    String root = relativeTo == null ? "" : "/" + relativeTo.asResolvedPath();
    Collection<FolderStore> fStores = Sets.newHashSetWithExpectedSize(folders.size());
    for (Folder folder : folders) {
        if (!folder.getPath().startsWith(root) || folder.getPath().equals(root)) {
            continue;
        }
        fStores.add(folder);
    }
    return fStores;
}
Also used : FolderStore(com.zimbra.common.mailbox.FolderStore) Folder(com.zimbra.cs.mailbox.Folder)

Aggregations

FolderStore (com.zimbra.common.mailbox.FolderStore)20 SearchFolderStore (com.zimbra.common.mailbox.SearchFolderStore)14 ServiceException (com.zimbra.common.service.ServiceException)13 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)12 AccountServiceException (com.zimbra.cs.account.AccountServiceException)11 MailboxStore (com.zimbra.common.mailbox.MailboxStore)9 MountpointStore (com.zimbra.common.mailbox.MountpointStore)4 Account (com.zimbra.cs.account.Account)3 ZSharedFolder (com.zimbra.client.ZSharedFolder)2 ACLGrant (com.zimbra.common.mailbox.ACLGrant)2 ItemIdentifier (com.zimbra.common.mailbox.ItemIdentifier)2 GuestAccount (com.zimbra.cs.account.GuestAccount)2 OperationContext (com.zimbra.cs.mailbox.OperationContext)2 ItemId (com.zimbra.cs.service.util.ItemId)2 ArrayList (java.util.ArrayList)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 ZFolder (com.zimbra.client.ZFolder)1 BaseFolderInfo (com.zimbra.common.mailbox.BaseFolderInfo)1 BaseItemInfo (com.zimbra.common.mailbox.BaseItemInfo)1 ExistingParentFolderStoreAndUnmatchedPart (com.zimbra.common.mailbox.ExistingParentFolderStoreAndUnmatchedPart)1