Search in sources :

Example 16 with Mountpoint

use of com.zimbra.cs.mailbox.Mountpoint in project zm-mailbox by Zimbra.

the class MailDocumentHandler method getProxyTarget.

protected static ItemId getProxyTarget(ZimbraSoapContext zsc, OperationContext octxt, ItemId iid, boolean checkMountpoint) throws ServiceException {
    if (zsc == null || iid == null) {
        return null;
    }
    Account acct = getRequestedAccount(zsc);
    if (!iid.belongsTo(acct)) {
        return iid;
    }
    if (!checkMountpoint || !Provisioning.onLocalServer(acct)) {
        return null;
    }
    Mailbox mbox = getRequestedMailbox(zsc);
    MailItem item = mbox.getItemById(octxt, iid.getId(), MailItem.Type.UNKNOWN);
    if (!(item instanceof Mountpoint)) {
        return null;
    }
    return ((Mountpoint) item).getTarget();
}
Also used : Account(com.zimbra.cs.account.Account) MailItem(com.zimbra.cs.mailbox.MailItem) Mailbox(com.zimbra.cs.mailbox.Mailbox) Mountpoint(com.zimbra.cs.mailbox.Mountpoint)

Example 17 with Mountpoint

use of com.zimbra.cs.mailbox.Mountpoint in project zm-mailbox by Zimbra.

the class ToXML method encodeFolder.

public static Element encodeFolder(Element parent, ItemIdFormatter ifmt, OperationContext octxt, Folder folder, int fields, boolean exposeAclAccessKey) throws ServiceException {
    if (folder instanceof SearchFolder) {
        return encodeSearchFolder(parent, ifmt, (SearchFolder) folder, fields);
    } else if (folder instanceof Mountpoint) {
        return encodeMountpoint(parent, ifmt, octxt, (Mountpoint) folder, fields);
    }
    Element elem = parent.addNonUniqueElement(MailConstants.E_FOLDER);
    encodeFolderCommon(elem, ifmt, folder, fields);
    if (needToOutput(fields, Change.SIZE)) {
        int deleted = folder.getDeletedCount();
        elem.addAttribute(MailConstants.A_NUM, folder.getItemCount() - deleted);
        if (deleted > 0) {
            elem.addAttribute(MailConstants.A_IMAP_NUM, folder.getItemCount());
        }
        elem.addAttribute(MailConstants.A_SIZE, folder.getTotalSize());
        elem.addAttribute(MailConstants.A_IMAP_MODSEQ, folder.getImapMODSEQ());
        elem.addAttribute(MailConstants.A_IMAP_UIDNEXT, folder.getImapUIDNEXT());
    }
    if (needToOutput(fields, Change.URL)) {
        String url = folder.getUrl();
        if (!url.isEmpty() || fields != NOTIFY_FIELDS) {
            // Note: in this case, a url on a folder object
            // is not a url to the folder, but the url to another item that's
            // external of the mail system. In most cases this is a 'synced' folder
            // that is either RSS or a remote calendar object
            elem.addAttribute(MailConstants.A_URL, HttpUtil.sanitizeURL(url));
        }
    }
    Mailbox mbox = folder.getMailbox();
    boolean remote = octxt != null && octxt.isDelegatedRequest(mbox);
    boolean canAdminister = !remote;
    boolean canDelete = canAdminister;
    if (remote) {
        // return effective permissions only for remote folders
        String perms = encodeEffectivePermissions(folder, octxt);
        elem.addAttribute(MailConstants.A_RIGHTS, perms);
        canAdminister = perms != null && perms.indexOf(ACL.ABBR_ADMIN) != -1;
        // Need to know retention policy if grantees can delete from a folder so clients can warn
        // them when they try to delete something within the retention period
        canDelete = canAdminister || (perms != null && perms.indexOf(ACL.ABBR_DELETE) != -1);
    }
    if (canAdminister) {
        // return full ACLs for folders we have admin rights on
        if (needToOutput(fields, Change.ACL)) {
            if (fields != NOTIFY_FIELDS || folder.isTagged(Flag.FlagInfo.NO_INHERIT)) {
                encodeACL(octxt, elem, folder.getEffectiveACL(), exposeAclAccessKey);
            }
        }
    }
    if (canDelete) {
        if (needToOutput(fields, Change.RETENTION_POLICY)) {
            RetentionPolicy rp = folder.getRetentionPolicy();
            if (fields != NOTIFY_FIELDS || rp.isSet()) {
                // Only output retention policy if it's being modified, or if we're returning all
                // folder data and policy is set.
                encodeRetentionPolicy(elem, RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(folder.getAccount(), rp));
            }
        }
    }
    return elem;
}
Also used : Mailbox(com.zimbra.cs.mailbox.Mailbox) Element(com.zimbra.common.soap.Element) SearchFolder(com.zimbra.cs.mailbox.SearchFolder) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) RetentionPolicy(com.zimbra.soap.mail.type.RetentionPolicy) Mountpoint(com.zimbra.cs.mailbox.Mountpoint)

Example 18 with Mountpoint

use of com.zimbra.cs.mailbox.Mountpoint in project zm-mailbox by Zimbra.

the class UserServletUtil method resolveItem.

/*
     * Parses the pathInfo, then returns MailItem corresponding to the resource in pathInfo.
     *
     * If the formatter does not require authentication, e.g. IfbFormatter,
     * then the path resolution is skipped and returns null.  That's because
     * IfbFormatter does not internally use the resource identified in the URL.
     * It gets the ifb information directly from the Mailbox.
     *
     * If the formatter declares that the authentication is not required, it's
     * the formatter's responsibility to make sure the MailItems returned to
     * the clients has gone through the access checks.
     *
     */
public static MailItem resolveItem(UserServletContext context, boolean checkExtension) throws ServiceException {
    if (context.formatter != null && !context.formatter.requiresAuth() && !FormatType.FREE_BUSY.equals(context.formatter.getType())) {
        return null;
    }
    if (context.formatter != null && context.formatter.getType() == FormatType.MOBILE_CONFIG) {
        return null;
    }
    Mailbox mbox = context.targetMailbox;
    // special-case the fetch-by-IMAP-id option
    if (context.imapId > 0) {
        // fetch the folder from the path
        Folder folder = mbox.getFolderByPath(context.opContext, context.itemPath);
        // and then fetch the item from the "imap_id" query parameter
        return mbox.getItemByImapId(context.opContext, context.imapId, folder.getId());
    }
    if (context.itemId != null) {
        OperationContext opContext = null;
        if (context.fromDumpster && context.isUsingAdminPrivileges()) {
            // should have the admin rights to search dumpster
            // use the authToken passed by invoker to generate a new one
            opContext = new OperationContext(context.authToken);
        } else {
            // use the opContext generated from account
            opContext = context.opContext;
        }
        context.target = mbox.getItemById(opContext, context.itemId.getId(), MailItem.Type.UNKNOWN, context.fromDumpster);
        context.itemPath = context.target.getPath();
        if (context.target instanceof Mountpoint || context.extraPath == null || context.extraPath.equals(""))
            return context.target;
        if (context.itemPath == null)
            throw MailServiceException.NO_SUCH_ITEM("?id=" + context.itemId + "&name=" + context.extraPath);
        context.target = null;
        context.itemId = null;
    }
    if (context.extraPath != null && !context.extraPath.equals("")) {
        context.itemPath = (context.itemPath + '/' + context.extraPath).replaceAll("//+", "/");
        context.extraPath = null;
    }
    if (FormatType.FREE_BUSY.equals(context.format) || FormatType.IFB.equals(context.format)) {
        try {
            // Do the get as mailbox owner to circumvent ACL system.
            context.target = mbox.getItemByPath(null, context.itemPath);
        } catch (ServiceException e) {
            if (!(e instanceof NoSuchItemException))
                throw e;
        }
    } else {
        // first, try the full requested path
        ServiceException failure = null;
        try {
            context.target = mbox.getItemByPath(context.opContext, context.itemPath);
        } catch (ServiceException e) {
            if (!(e instanceof NoSuchItemException) && !e.getCode().equals(ServiceException.PERM_DENIED))
                throw e;
            failure = e;
        }
        if (context.target == null) {
            // then we need to proxy the request to the sharer's mailbox.
            try {
                // to search for the mountpoint we use admin rights on the user's mailbox.
                // this is done so that MailItems in the mountpoint can be resolved
                // according to the ACL stored in the owner's Folder.  when a mountpoint
                // is found, then the request is proxied to the owner's mailbox host,
                // and the current requestor's credential is used to validate against
                // the ACL.
                Pair<Folder, String> match = mbox.getFolderByPathLongestMatch(null, Mailbox.ID_FOLDER_USER_ROOT, context.itemPath);
                Folder reachable = match.getFirst();
                if (reachable instanceof Mountpoint) {
                    context.target = reachable;
                    context.itemPath = reachable.getPath();
                    context.extraPath = match.getSecond();
                }
            } catch (ServiceException e) {
            }
        }
        if (context.target == null) {
            // if they asked for something like "calendar.csv" (where "calendar" was the folder name), try again minus the extension
            int dot = context.itemPath.lastIndexOf('.'), slash = context.itemPath.lastIndexOf('/');
            if (checkExtension && context.format == null && dot != -1 && dot > slash) {
                /* if path == /foo/bar/baz.html, then
                     *      format -> html
                     *      path   -> /foo/bar/baz  */
                String unsuffixedPath = context.itemPath.substring(0, dot);
                try {
                    context.format = FormatType.fromString(context.itemPath.substring(dot + 1));
                    if (context.format != null) {
                        context.formatter = FormatterFactory.mFormatters.get(context.format);
                    }
                    if (context.formatter != null && !context.formatter.requiresAuth()) {
                        // Do the get as mailbox owner to circumvent ACL system.
                        context.target = mbox.getItemByPath(null, unsuffixedPath);
                    } else {
                        context.target = mbox.getItemByPath(context.opContext, unsuffixedPath);
                    }
                    context.itemPath = unsuffixedPath;
                } catch (ServiceException e) {
                }
            }
        }
        if (context.target == null)
            throw failure;
    }
    return context.target;
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Mailbox(com.zimbra.cs.mailbox.Mailbox) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) Folder(com.zimbra.cs.mailbox.Folder) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) Mountpoint(com.zimbra.cs.mailbox.Mountpoint)

Example 19 with Mountpoint

use of com.zimbra.cs.mailbox.Mountpoint in project zm-mailbox by Zimbra.

the class ItemId method groupFoldersByAccount.

// groups folders by account id
// value is list of folder id integers
// mountpoints in local account are fully resolved to real folder in target account
public static Map<String, List<Integer>> groupFoldersByAccount(OperationContext octxt, Mailbox mbox, List<ItemId> folderIids) throws ServiceException {
    Map<String, List<Integer>> foldersMap = new HashMap<String, List<Integer>>();
    for (ItemId iidFolder : folderIids) {
        String targetAccountId = iidFolder.getAccountId();
        int folderId = iidFolder.getId();
        try {
            if (mbox.getAccountId().equals(targetAccountId)) {
                boolean isMountpoint = true;
                int hopCount = 0;
                // resolve local mountpoint to a real folder; deal with possible mountpoint chain
                while (isMountpoint && hopCount < ZimbraSoapContext.MAX_HOP_COUNT) {
                    Folder folder = mbox.getFolderById(octxt, folderId);
                    isMountpoint = folder instanceof Mountpoint;
                    if (isMountpoint) {
                        Mountpoint mp = (Mountpoint) folder;
                        folderId = mp.getRemoteId();
                        if (!mp.isLocal()) {
                            // done resolving if pointing to a different account
                            targetAccountId = mp.getOwnerId();
                            Account targetAcct = Provisioning.getInstance().get(Key.AccountBy.id, targetAccountId);
                            if (targetAcct == null) {
                                throw MailServiceException.NO_SUCH_MOUNTPOINT(mp.getId(), mp.getOwnerId(), mp.getRemoteId(), AccountServiceException.NO_SUCH_ACCOUNT(targetAccountId));
                            }
                            break;
                        }
                        hopCount++;
                    }
                }
                if (hopCount >= ZimbraSoapContext.MAX_HOP_COUNT)
                    throw MailServiceException.TOO_MANY_HOPS(iidFolder);
            }
            List<Integer> folderList = foldersMap.get(targetAccountId);
            if (folderList == null) {
                folderList = new ArrayList<Integer>();
                foldersMap.put(targetAccountId, folderList);
            }
            folderList.add(folderId);
        } catch (ServiceException e) {
            String ecode = e.getCode();
            ItemIdFormatter ifmt = new ItemIdFormatter(targetAccountId, targetAccountId, false);
            if (ecode.equals(ServiceException.PERM_DENIED)) {
                // share permission was revoked
                ZimbraLog.calendar.warn("Ignorable permission error %s", ifmt.formatItemId(folderId), e);
            } else if (ecode.equals(MailServiceException.NO_SUCH_FOLDER)) {
                // shared calendar folder was deleted by the owner
                ZimbraLog.calendar.warn("Ignoring deleted folder %s", ifmt.formatItemId(folderId));
            } else {
                throw e;
            }
        }
    }
    return foldersMap;
}
Also used : Account(com.zimbra.cs.account.Account) HashMap(java.util.HashMap) Folder(com.zimbra.cs.mailbox.Folder) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) ArrayList(java.util.ArrayList) List(java.util.List) Mountpoint(com.zimbra.cs.mailbox.Mountpoint)

Example 20 with Mountpoint

use of com.zimbra.cs.mailbox.Mountpoint in project zm-mailbox by Zimbra.

the class SoapSession method putQueuedNotifications.

/**
 * Write a single instance of the PendingLocalModifications structure into the
 *  passed-in <ctxt> block.
 */
protected void putQueuedNotifications(Mailbox mbox, QueuedNotifications ntfn, Element parent, ZimbraSoapContext zsc) {
    // create the base "notify" block:  <notify seq="6"/>
    Element eNotify = parent.addNonUniqueElement(ZimbraNamespace.E_NOTIFY);
    if (ntfn.getSequence() > 0) {
        eNotify.addAttribute(HeaderConstants.A_SEQNO, ntfn.getSequence());
    }
    OperationContext octxt = null;
    try {
        octxt = DocumentHandler.getOperationContext(zsc, this);
    } catch (ServiceException e) {
        ZimbraLog.session.warn("error fetching operation context for: " + zsc.getAuthtokenAccountId(), e);
        return;
    }
    boolean debug = ZimbraLog.session.isDebugEnabled();
    PendingLocalModifications pms = ntfn.mMailboxChanges;
    RemoteNotifications rns = ntfn.mRemoteChanges;
    Element eDeleted = eNotify.addUniqueElement(ZimbraNamespace.E_DELETED);
    StringBuilder deletedIds = new StringBuilder();
    if (pms != null && pms.deleted != null && pms.deleted.size() > 0) {
        for (ModificationKey mkey : pms.deleted.keySet()) {
            addDeletedNotification(mkey, deletedIds);
        }
    }
    if (rns != null && rns.deleted != null) {
        deletedIds.append(deletedIds.length() == 0 ? "" : ",").append(rns.deleted);
    }
    boolean hasLocalCreates = pms != null && pms.created != null && !pms.created.isEmpty();
    boolean hasRemoteCreates = rns != null && rns.created != null && !rns.created.isEmpty();
    boolean hasLocalModifies = pms != null && pms.modified != null && !pms.modified.isEmpty();
    boolean hasRemoteModifies = rns != null && rns.modified != null && !rns.modified.isEmpty();
    if (SoapTransport.NotificationFormat.valueOf(zsc.getNotificationFormat()) == SoapTransport.NotificationFormat.IMAP) {
        try {
            AccountWithModifications info = new AccountWithModifications(zsc.getAuthtokenAccountId(), mbox.getLastChangeID());
            Map<Integer, PendingFolderModifications> folderMods = PendingModifications.encodeIMAPFolderModifications(pms);
            info.setPendingFolderModifications(folderMods.values());
            eNotify.addUniqueElement(JaxbUtil.jaxbToElement(info, eNotify.getFactory()));
        } catch (ContainerException | ServiceException e) {
            ZimbraLog.session.error("Failed to encode IMAP notifications for a SOAP session ", e);
        }
    }
    if (hasLocalCreates || hasRemoteCreates) {
        Element eCreated = eNotify.addUniqueElement(ZimbraNamespace.E_CREATED);
        if (hasLocalCreates) {
            for (BaseItemInfo item : pms.created.values()) {
                if (item instanceof MailItem) {
                    MailItem mi = (MailItem) item;
                    ItemIdFormatter ifmt = new ItemIdFormatter(mAuthenticatedAccountId, mi.getMailbox(), false);
                    try {
                        Element elem = ToXML.encodeItem(eCreated, ifmt, octxt, mi, ToXML.NOTIFY_FIELDS);
                        // special-case notifications for new mountpoints in the authenticated user's mailbox
                        if (item instanceof Mountpoint && mbox == mi.getMailbox()) {
                            Map<ItemId, Pair<Boolean, Element>> mountpoints = new HashMap<ItemId, Pair<Boolean, Element>>(2);
                            expandLocalMountpoint(octxt, (Mountpoint) mi, eCreated.getFactory(), mountpoints);
                            expandRemoteMountpoints(octxt, zsc, mountpoints);
                            transferMountpointContents(elem, octxt, mountpoints);
                        }
                    } catch (ServiceException e) {
                        ZimbraLog.session.warn("error encoding item " + mi.getId(), e);
                        return;
                    }
                }
            }
            // sanity-check the returned element
            if (!eCreated.hasChildren() && debug) {
                ZimbraLog.session.debug("no serialied creates for item set: %s", pms.created.keySet());
            }
        }
        if (hasRemoteCreates) {
            if (debug) {
                ZimbraLog.session.debug("adding %d proxied creates", rns.created.size());
            }
            for (Element elt : rns.created) {
                if (encodingMatches(parent, elt)) {
                    eCreated.addElement(elt.clone().detach());
                } else {
                    ZimbraLog.session.warn("unable to add remote notification due to mismatched SOAP protocol");
                }
            }
        }
    }
    ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
    if (hasLocalModifies || hasRemoteModifies) {
        Element eModified = eNotify.addUniqueElement(ZimbraNamespace.E_MODIFIED);
        if (hasLocalModifies) {
            for (Change chg : pms.modified.values()) {
                if (chg.why != 0 && chg.what instanceof MailItem) {
                    MailItem item = (MailItem) chg.what;
                    try {
                        Element elt = ToXML.encodeItem(eModified, ifmt, octxt, item, chg.why);
                        if (elt == null) {
                            ModificationKey mkey = new PendingLocalModifications.ModificationKey(item);
                            addDeletedNotification(mkey, deletedIds);
                            if (debug) {
                                ZimbraLog.session.debug("marking nonserialized item as a delete: %s", mkey);
                            }
                        }
                    } catch (ServiceException e) {
                        ZimbraLog.session.warn("error encoding item " + item.getId(), e);
                        return;
                    }
                } else if (chg.why != 0 && chg.what instanceof Mailbox) {
                    ToXML.encodeMailbox(eModified, octxt, (Mailbox) chg.what, chg.why);
                }
            }
            // sanity-check the returned element
            if (!eModified.hasChildren() && debug) {
                ZimbraLog.session.debug("no serialied modifies for item set: %s", pms.modified.keySet());
            }
        }
        if (hasRemoteModifies) {
            if (debug) {
                ZimbraLog.session.debug("adding %d proxied modifies", rns.modified.size());
            }
            for (Element elt : rns.modified) {
                if (encodingMatches(parent, elt)) {
                    eModified.addElement(elt.clone().detach());
                } else {
                    ZimbraLog.session.warn("unable to add remote notification due to mismatched SOAP protocol");
                }
            }
        }
    }
    if (rns != null && rns.activities != null && !rns.activities.isEmpty()) {
        for (Element elt : rns.activities) {
            if (encodingMatches(parent, elt)) {
                eNotify.addElement(elt.clone().detach());
            } else {
                ZimbraLog.session.warn("unable to add remote notification due to mismatched SOAP protocol");
            }
        }
    }
    putExtraNotifications(ntfn, eNotify, ifmt);
    if (deletedIds == null || deletedIds.length() == 0) {
        eDeleted.detach();
    } else {
        eDeleted.addAttribute(A_ID, deletedIds.toString());
    }
}
Also used : AccountWithModifications(com.zimbra.soap.type.AccountWithModifications) BaseItemInfo(com.zimbra.common.mailbox.BaseItemInfo) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) HashMap(java.util.HashMap) Element(com.zimbra.common.soap.Element) ModificationKey(com.zimbra.cs.session.PendingModifications.ModificationKey) ItemId(com.zimbra.cs.service.util.ItemId) Mailbox(com.zimbra.cs.mailbox.Mailbox) ContainerException(com.zimbra.common.soap.Element.ContainerException) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) Pair(com.zimbra.common.util.Pair) OperationContext(com.zimbra.cs.mailbox.OperationContext) Change(com.zimbra.cs.session.PendingModifications.Change) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) PendingFolderModifications(com.zimbra.soap.mail.type.PendingFolderModifications)

Aggregations

Mountpoint (com.zimbra.cs.mailbox.Mountpoint)43 Folder (com.zimbra.cs.mailbox.Folder)30 ServiceException (com.zimbra.common.service.ServiceException)23 Mailbox (com.zimbra.cs.mailbox.Mailbox)18 Account (com.zimbra.cs.account.Account)17 MailItem (com.zimbra.cs.mailbox.MailItem)14 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)14 ZFolder (com.zimbra.client.ZFolder)11 ItemId (com.zimbra.cs.service.util.ItemId)11 ZMailbox (com.zimbra.client.ZMailbox)8 Element (com.zimbra.common.soap.Element)8 OperationContext (com.zimbra.cs.mailbox.OperationContext)8 IOException (java.io.IOException)8 HashMap (java.util.HashMap)8 Provisioning (com.zimbra.cs.account.Provisioning)6 SearchFolder (com.zimbra.cs.mailbox.SearchFolder)6 ZMountpoint (com.zimbra.client.ZMountpoint)5 Pair (com.zimbra.common.util.Pair)5 NoSuchItemException (com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException)5 ItemIdFormatter (com.zimbra.cs.service.util.ItemIdFormatter)5