Search in sources :

Example 1 with FolderStore

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

the class ImapHandler method doLSUB.

private boolean doLSUB(String tag, String referenceName, String mailboxName) throws ImapException, IOException {
    checkCommandThrottle(new LsubCommand(referenceName, mailboxName));
    if (!checkState(tag, State.AUTHENTICATED)) {
        return true;
    }
    Pair<String, Pattern> resolved = resolvePath(referenceName, mailboxName);
    String resolvedPath = resolved.getFirst();
    Pattern pattern = resolved.getSecond();
    Pattern childPattern = Pattern.compile(pattern.pattern() + "/.*");
    ImapPath patternPath = new ImapPath(resolvedPath, credentials, ImapPath.Scope.UNPARSED);
    List<String> subscriptions = null;
    try {
        // you cannot access your own mailbox via the /home/username mechanism
        String owner = patternPath.getOwner();
        if (owner == null || owner.indexOf('*') != -1 || owner.indexOf('%') != -1 || !patternPath.belongsTo(credentials)) {
            Map<SubscribedImapPath, Boolean> hits = new HashMap<SubscribedImapPath, Boolean>();
            if (owner == null) {
                MailboxStore mbox = credentials.getMailbox();
                boolean isMailFolders = Provisioning.getInstance().getLocalServer().isImapDisplayMailFoldersOnly();
                for (FolderStore folder : mbox.getUserRootSubfolderHierarchy(getContext())) {
                    // chat has item type of message.hence ignoring the chat folder by name.
                    if ((isMailFolders) && (folder.isChatsFolder() || (folder.getName().equals("Chats")))) {
                        continue;
                    }
                    String fAcctId = folder.getFolderItemIdentifier().accountId;
                    if ((fAcctId != null) && !fAcctId.equals(credentials.getAccountId())) {
                        // ignore imapSubscribed flag on remote folders - they apply to the remote acct
                        continue;
                    }
                    if (folder.isIMAPSubscribed()) {
                        checkSubscription(new SubscribedImapPath(new ImapPath(null, folder, credentials)), pattern, childPattern, hits);
                    }
                }
            }
            Set<String> remoteSubscriptions = credentials.listSubscriptions();
            if (remoteSubscriptions != null && !remoteSubscriptions.isEmpty()) {
                for (String sub : remoteSubscriptions) {
                    ImapPath subscribed = new ImapPath(sub, credentials);
                    if ((owner == null) == (subscribed.getOwner() == null)) {
                        checkSubscription(new SubscribedImapPath(subscribed), pattern, childPattern, hits);
                    }
                }
            }
            subscriptions = new ArrayList<String>(hits.size());
            for (Entry<SubscribedImapPath, Boolean> hit : hits.entrySet()) {
                String attrs = hit.getValue() ? "" : "\\NoSelect";
                subscriptions.add("LSUB (" + attrs + ") \"/\" " + hit.getKey().asUtf7String());
            }
        }
    } catch (ServiceException e) {
        ZimbraLog.imap.warn("LSUB failed", e);
        sendNO(tag, "LSUB failed");
        return canContinue(e);
    }
    if (subscriptions != null) {
        for (String sub : subscriptions) {
            sendUntagged(sub);
        }
    }
    sendNotifications(true, false);
    sendOK(tag, "LSUB completed");
    return true;
}
Also used : Pattern(java.util.regex.Pattern) MailboxStore(com.zimbra.common.mailbox.MailboxStore) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException)

Example 2 with FolderStore

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

the class ImapHandler method status.

private String status(ImapPath path, byte status) throws ImapException, ServiceException {
    StringBuilder data = new StringBuilder("STATUS ").append(path.asUtf7String()).append(" (");
    int empty = data.length();
    int messages;
    int recent;
    int uidnext;
    int uvv;
    int unread;
    int modseq;
    MailboxStore mboxStore = path.getOwnerMailbox();
    if (mboxStore != null) {
        FolderStore folder = path.getFolder();
        if (folder == null) {
            throw MailServiceException.NO_SUCH_FOLDER(path.asImapPath());
        }
        ImapFolder i4folder = getSelectedFolder();
        messages = folder.getImapMessageCount();
        if ((status & StatusDataItemNames.STATUS_RECENT) == 0) {
            recent = -1;
        } else if (messages == 0) {
            recent = 0;
        } else if (i4folder != null && i4folder.getItemIdentifier().sameAndFullyDefined(folder.getFolderItemIdentifier())) {
            recent = i4folder.getRecentCount();
        } else if (i4folder != null && path.isEquivalent(i4folder.getPath())) {
            recent = i4folder.getRecentCount();
        } else {
            ImapMailboxStore imapStore = path.getOwnerImapMailboxStore();
            recent = imapStore.getImapRECENT(this.getContext(), folder);
        }
        uidnext = folder.isSearchFolder() ? -1 : folder.getImapUIDNEXT();
        uvv = folder.getUIDValidity();
        unread = folder.getImapUnreadCount();
        modseq = folder.isSearchFolder() ? 0 : folder.getImapMODSEQ();
        ZimbraLog.imap.debug("STATUS for %s. unread %d, recent %d, count %d", folder.getPath(), unread, recent, messages);
    } else {
        throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
    }
    if (messages >= 0 && (status & StatusDataItemNames.STATUS_MESSAGES) != 0) {
        data.append(data.length() != empty ? " " : "").append("MESSAGES ").append(messages);
    }
    if (recent >= 0 && (status & StatusDataItemNames.STATUS_RECENT) != 0) {
        data.append(data.length() != empty ? " " : "").append("RECENT ").append(recent);
    }
    // note: we're not supporting UIDNEXT for search folders; see the comments in selectFolder()
    if (uidnext > 0 && (status & StatusDataItemNames.STATUS_UIDNEXT) != 0) {
        data.append(data.length() != empty ? " " : "").append("UIDNEXT ").append(uidnext);
    }
    if (uvv > 0 && (status & StatusDataItemNames.STATUS_UIDVALIDITY) != 0) {
        data.append(data.length() != empty ? " " : "").append("UIDVALIDITY ").append(uvv);
    }
    if (unread >= 0 && (status & StatusDataItemNames.STATUS_UNSEEN) != 0) {
        data.append(data.length() != empty ? " " : "").append("UNSEEN ").append(unread);
    }
    if (modseq >= 0 && (status & StatusDataItemNames.STATUS_HIGHESTMODSEQ) != 0) {
        data.append(data.length() != empty ? " " : "").append("HIGHESTMODSEQ ").append(modseq);
    }
    return data.append(')').toString();
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore)

Example 3 with FolderStore

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

the class ImapHandler method doDELETEACL.

private boolean doDELETEACL(String tag, ImapPath path, String principal) throws IOException {
    if (!checkState(tag, State.AUTHENTICATED)) {
        return true;
    }
    try {
        // make sure the requester has sufficient permissions to make the request
        if ((path.getFolderRights() & ACL.RIGHT_ADMIN) == 0) {
            ZimbraLog.imap.info("DELETEACL failed: user does not have admin access: " + path);
            sendNO(tag, "DELETEACL failed");
            return true;
        }
        // figure out whose permissions are being revoked
        GranteeIdAndType grantee = getPrincipalGranteeInfo(principal);
        if (grantee.id == null) {
            ZimbraLog.imap.info("DELETEACL failed: cannot resolve principal: %s", principal);
            sendNO(tag, "DELETEACL failed");
            return true;
        }
        // and revoke the permissions appropriately
        MailboxStore mboxStore = path.getOwnerMailbox();
        if (mboxStore != null) {
            FolderStore folder = path.getFolder();
            if (!folder.getACLGrants().isEmpty()) {
                mboxStore.modifyFolderRevokeGrant(getContext(), folder.getFolderIdAsString(), grantee.id);
                if (grantee.id == GuestAccount.GUID_AUTHUSER) {
                    mboxStore.modifyFolderRevokeGrant(getContext(), folder.getFolderIdAsString(), GuestAccount.GUID_PUBLIC);
                }
            }
        }
    } catch (ServiceException e) {
        if (e.getCode().equals(ServiceException.PERM_DENIED)) {
            ZimbraLog.imap.info("DELETEACL failed: permission denied on folder: %s", path);
        } else if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
            ZimbraLog.imap.info("DELETEACL failed: no such folder: %s", path);
        } else if (e.getCode().equals(AccountServiceException.NO_SUCH_ACCOUNT)) {
            ZimbraLog.imap.info("DELETEACL failed: no such account: %s", principal);
        } else {
            ZimbraLog.imap.warn("DELETEACL failed", e);
        }
        sendNO(tag, "DELETEACL failed");
        return true;
    }
    sendNotifications(true, false);
    sendOK(tag, "DELETEACL 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) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore)

Example 4 with FolderStore

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

the class ImapHandler method doSETACL.

private boolean doSETACL(String tag, ImapPath path, String principal, String i4rights, StoreAction action) throws IOException {
    if (!checkState(tag, State.AUTHENTICATED))
        return true;
    // RFC 4314 2: "If rights are tied in an implementation, the implementation must be
    // conservative in granting rights in response to SETACL commands--unless
    // all rights in a tied set are specified, none of that set should be
    // included in the ACL entry for that identifier."
    short rights = 0;
    for (int i = 0; i < i4rights.length(); i++) {
        char c = i4rights.charAt(i);
        if (IMAP_READ_RIGHTS.indexOf(c) != -1) {
            if (allRightsPresent(i4rights, IMAP_READ_RIGHTS))
                rights |= ACL.RIGHT_READ;
        } else if (IMAP_WRITE_RIGHTS.indexOf(c) != -1) {
            if (allRightsPresent(i4rights, IMAP_WRITE_RIGHTS))
                rights |= ACL.RIGHT_WRITE;
        } else if (IMAP_INSERT_RIGHTS.indexOf(c) != -1) {
            if (allRightsPresent(i4rights, IMAP_INSERT_RIGHTS))
                rights |= ACL.RIGHT_INSERT;
        } else if (IMAP_DELETE_RIGHTS.indexOf(c) != -1) {
            if (allRightsPresent(i4rights, IMAP_DELETE_RIGHTS))
                rights |= ACL.RIGHT_DELETE;
        } else if (IMAP_ADMIN_RIGHTS.indexOf(c) != -1) {
            if (allRightsPresent(i4rights, IMAP_ADMIN_RIGHTS))
                rights |= ACL.RIGHT_ADMIN;
        } else {
            // RFC 4314 3.1: "Note that an unrecognized right MUST cause the command to return
            // the BAD response.  In particular, the server MUST NOT silently
            // ignore unrecognized rights."
            ZimbraLog.imap.info("SETACL failed: invalid rights string: %s", i4rights);
            sendBAD(tag, "SETACL failed: invalid right");
            return true;
        }
    }
    try {
        // make sure the requester has sufficient permissions to make the request
        if ((path.getFolderRights() & ACL.RIGHT_ADMIN) == 0) {
            ZimbraLog.imap.info("SETACL failed: user does not have admin access: %s", path);
            sendNO(tag, "SETACL failed");
            return true;
        }
        // detect a no-op early and short-circuit out here
        if (action != StoreAction.REPLACE && rights == 0) {
            sendNotifications(true, false);
            sendOK(tag, "SETACL completed");
            return true;
        }
        // figure out who's being granted permissions
        GranteeIdAndType grantee = getPrincipalGranteeInfo(principal);
        if (grantee.id == null) {
            ZimbraLog.imap.info("SETACL failed: cannot resolve principal: %s", principal);
            sendNO(tag, "SETACL failed");
            return true;
        }
        // figure out the rights already granted on the folder
        short oldRights = 0;
        FolderStore folderStore = path.getFolder();
        if (null != folderStore) {
            for (ACLGrant grant : folderStore.getACLGrants()) {
                if (grantee.id.equalsIgnoreCase(grant.getGranteeId()) || (grantee.type == ACL.GRANTEE_AUTHUSER && (grant.getGrantGranteeType() == GrantGranteeType.all || grant.getGrantGranteeType() == GrantGranteeType.pub))) {
                    oldRights |= ACL.stringToRights(grant.getPermissions());
                }
            }
        }
        // calculate the new rights we want granted on the folder
        short newRights;
        if (action == StoreAction.REMOVE) {
            newRights = (short) (oldRights & ~rights);
        } else if (action == StoreAction.ADD) {
            newRights = (short) (oldRights | rights);
        } else {
            newRights = rights;
        }
        // and update the folder appropriately, if necessary
        if (newRights != oldRights) {
            MailboxStore mboxStore = path.getOwnerMailbox();
            mboxStore.modifyFolderGrant(getContext(), folderStore, GrantGranteeType.fromByte(grantee.type), grantee.id, ACL.rightsToString(newRights), null);
        }
    } catch (ServiceException e) {
        if (e.getCode().equals(ServiceException.PERM_DENIED)) {
            ZimbraLog.imap.info("SETACL failed: permission denied on folder: %s", path);
        } else if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
            ZimbraLog.imap.info("SETACL failed: no such folder: %s", path);
        } else if (e.getCode().equals(AccountServiceException.NO_SUCH_ACCOUNT)) {
            ZimbraLog.imap.info("SETACL failed: no such account: %s", principal);
        } else {
            ZimbraLog.imap.warn("SETACL failed", e);
        }
        sendNO(tag, "SETACL failed");
        return true;
    }
    sendNotifications(true, false);
    sendOK(tag, "SETACL 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) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore) ACLGrant(com.zimbra.common.mailbox.ACLGrant)

Example 5 with FolderStore

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

the class ImapHandler method doDELETE.

private boolean doDELETE(String tag, ImapPath path) throws IOException {
    if (!checkState(tag, State.AUTHENTICATED)) {
        return true;
    }
    try {
        if (!path.isVisible()) {
            throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
        }
        // don't want the DELETE to cause *this* connection to drop if the deleted folder is currently selected
        if (getState() == State.SELECTED) {
            ImapListener i4selected = getCurrentImapListener();
            if (i4selected != null && path.isEquivalent(i4selected.getPath())) {
                unsetSelectedFolder(true);
            } else if (imapProxy != null && path.isEquivalent(imapProxy.getPath())) {
                unsetSelectedFolder(true);
            }
        }
        MailboxStore mboxStore = path.getOwnerMailbox();
        if (path.useReferent()) {
            // when users try to remove mountpoints, the IMAP client hard-deletes the subfolders!
            // deal with this by only *pretending* to delete subfolders of mountpoints
            credentials.hideFolder(path);
            // even pretend-deleting the folder also unsubscribes from it...
            credentials.unsubscribe(path);
        } else if (null != mboxStore) {
            FolderStore folder = path.getFolder();
            if (!folder.isDeletable()) {
                throw ImapServiceException.CANNOT_DELETE_SYSTEM_FOLDER(folder.getPath());
            }
            if (!folder.hasSubfolders()) {
                mboxStore.deleteFolder(getContext(), folder.getFolderIdAsString());
                // deleting the folder also unsubscribes from it...
                credentials.unsubscribe(path);
            } else {
                // 6.3.4: "It is permitted to delete a name that has inferior hierarchical
                // names and does not have the \Noselect mailbox name attribute.
                // In this case, all messages in that mailbox are removed, and the
                // name will acquire the \Noselect mailbox name attribute."
                mboxStore.emptyFolder(getContext(), folder.getFolderIdAsString(), false);
            // FIXME: add \Deleted flag to folder
            }
        } else {
            throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
        }
    } catch (ServiceException e) {
        if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
            ZimbraLog.imap.info("DELETE failed: no such folder: %s", path);
        } else if (e.getCode().equals(AccountServiceException.NO_SUCH_ACCOUNT)) {
            ZimbraLog.imap.info("DELETE failed: no such account: %s", path);
        } else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
            ZimbraLog.imap.info("DELETE failed: folder not visible: %s", path);
        } else if (e.getCode().equals(ImapServiceException.CANT_DELETE_SYSTEM_FOLDER)) {
            ZimbraLog.imap.info("DELETE failed: system folder cannot be deleted: %s", path);
        } else if (e.getCode().equals(ServiceException.PERM_DENIED)) {
            ZimbraLog.imap.info("DELETE failed: permission denied: %s", path);
        } else {
            ZimbraLog.imap.warn("DELETE failed", e);
        }
        sendNO(tag, "DELETE failed");
        return canContinue(e);
    }
    sendNotifications(true, false);
    sendOK(tag, "DELETE 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) SearchFolderStore(com.zimbra.common.mailbox.SearchFolderStore) FolderStore(com.zimbra.common.mailbox.FolderStore)

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