Search in sources :

Example 1 with TargetConstraint

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

the class Mailbox method emptyFolder.

/**
 * @param removeTopLevelFolder - delete folder after it has been emptied
 */
private void emptyFolder(OperationContext octxt, int folderId, boolean removeTopLevelFolder, boolean removeSubfolders, TargetConstraint tcon) throws ServiceException {
    try {
        if (emptyFolderOpLock.tryLock() || emptyFolderOpLock.tryLock(Provisioning.getInstance().getLocalServer().getEmptyFolderOpTimeout(), TimeUnit.SECONDS)) {
            int batchSize = Provisioning.getInstance().getLocalServer().getMailEmptyFolderBatchSize();
            ZimbraLog.mailbox.debug("Emptying folder %s, removeTopLevelFolder=%b, removeSubfolders=%b, batchSize=%d", folderId, removeTopLevelFolder, removeSubfolders, batchSize);
            List<Integer> folderIds = new ArrayList<Integer>();
            if (!removeSubfolders) {
                folderIds.add(folderId);
            } else {
                List<Folder> folders = getFolderById(octxt, folderId).getSubfolderHierarchy();
                for (Folder folder : folders) {
                    folderIds.add(folder.getId());
                }
            }
            // Make sure that the user has the delete permission for all folders in the hierarchy.
            for (int id : folderIds) {
                if ((getEffectivePermissions(octxt, id, MailItem.Type.FOLDER) & ACL.RIGHT_DELETE) == 0) {
                    throw ServiceException.PERM_DENIED("not authorized to empty folder " + getFolderById(octxt, id).getPath());
                }
            }
            int lastChangeID = octxt != null && octxt.change != -1 ? octxt.change : getLastChangeID();
            // Delete the items in batches.  (1000 items by default)
            QueryParams params = new QueryParams();
            params.setFolderIds(folderIds).setModifiedSequenceBefore(lastChangeID + 1).setRowLimit(batchSize);
            boolean firstTime = true;
            do {
                // Give other threads a chance to use the mailbox between deletion batches.
                if (firstTime) {
                    firstTime = false;
                } else {
                    long sleepMillis = LC.empty_folder_batch_sleep_ms.longValue();
                    try {
                        ZimbraLog.mailbox.debug("emptyLargeFolder() sleeping for %dms", sleepMillis);
                        Thread.sleep(sleepMillis);
                    } catch (InterruptedException e) {
                        ZimbraLog.mailbox.warn("Sleep was interrupted", e);
                    }
                }
            } while (deletedBatchOfItemsInFolder(octxt, params, tcon));
            if ((removeTopLevelFolder || removeSubfolders) && (!folderIds.isEmpty())) {
                if (!removeTopLevelFolder) {
                    // 0th position is the folder being emptied
                    folderIds.remove(0);
                }
                if (!folderIds.isEmpty()) {
                    lock.lock();
                    try {
                        delete(octxt, ArrayUtil.toIntArray(folderIds), MailItem.Type.FOLDER, tcon, false, /* don't useEmptyForFolders */
                        null);
                    } finally {
                        lock.release();
                    }
                }
            }
        } else {
            ZimbraLog.mailbox.info("Empty large folder operation canceled because previous empty folder operation is in progress");
            throw ServiceException.ALREADY_IN_PROGRESS("Empty Folder operation is in progress. Please wait for the operation to complete");
        }
    } catch (InterruptedException e) {
        ZimbraLog.mailbox.warn("Empty folder operation interupted while acquiring emptyFolderOpLock", e);
        throw ServiceException.ALREADY_IN_PROGRESS("Empty Folder operation is in progress. Please wait for the operation to complete");
    } finally {
        if (emptyFolderOpLock.isHeldByCurrentThread()) {
            emptyFolderOpLock.unlock();
        }
    }
}
Also used : CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) QueryParams(com.zimbra.cs.db.DbMailItem.QueryParams) CreateFolder(com.zimbra.cs.redolog.op.CreateFolder) ZFolder(com.zimbra.client.ZFolder) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint)

Example 2 with TargetConstraint

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

the class Mailbox method delete.

/**
 * Delete the <tt>MailItem</tt>s with the given ids.  If there is no <tt>MailItem</tt> for a given id, that id is
 * ignored.  If the id maps to an existing <tt>MailItem</tt> of an incompatible type, however, an error is thrown.
 *
 * @param octxt operation context or {@code null}
 * @param itemIds item ids
 * @param type item type or {@link MailItem.Type#UNKNOWN}
 * @param tcon target constraint or {@code null}
 * @param useEmptyForFolders empty folder {@code true} or {@code false}
 * @param nonExistingItems object of {@link ArrayList} or {@code null}
 */
private void delete(OperationContext octxt, int[] itemIds, MailItem.Type type, TargetConstraint tcon, boolean useEmptyForFolders, List<Integer> nonExistingItems) throws ServiceException {
    DeleteItem redoRecorder = new DeleteItem(mId, itemIds, type, tcon);
    List<Integer> folderIds = Lists.newArrayList();
    boolean success = false;
    try {
        beginTransaction("delete", octxt, redoRecorder);
        setOperationTargetConstraint(tcon);
        for (int id : itemIds) {
            if (id == ID_AUTO_INCREMENT) {
                continue;
            }
            MailItem item;
            try {
                item = getItemById(id, MailItem.Type.UNKNOWN);
            } catch (NoSuchItemException nsie) {
                if (nonExistingItems != null) {
                    nonExistingItems.add(id);
                }
                // trying to delete nonexistent things is A-OK!
                continue;
            }
            // however, trying to delete messages and passing in a folder ID is not OK
            if (!MailItem.isAcceptableType(type, item.getType())) {
                throw MailItem.noSuchItem(id, type);
            } else if (!checkItemChangeID(item) && item instanceof Tag) {
                throw MailServiceException.MODIFY_CONFLICT();
            }
            if (useEmptyForFolders && MailItem.Type.FOLDER.equals(item.getType())) {
                // removed later to allow batching delete of contents in there own transactions
                folderIds.add(id);
            } else {
                // delete the item, but don't write the tombstone until we're finished...
                item.delete(false);
            }
        }
        // deletes have already been collected, so fetch the tombstones and write once
        TypedIdList tombstones = collectPendingTombstones();
        if (tombstones != null && !tombstones.isEmpty()) {
            DbMailItem.writeTombstones(this, tombstones);
        }
        success = true;
    } finally {
        endTransaction(success);
    }
    for (Integer folderId : folderIds) {
        emptyFolder(octxt, folderId, true, /* removeTopLevelFolder */
        true, /* removeSubfolders */
        tcon);
    }
}
Also used : DbMailItem(com.zimbra.cs.db.DbMailItem) ZimbraMailItem(com.zimbra.common.mailbox.ZimbraMailItem) DeleteItem(com.zimbra.cs.redolog.op.DeleteItem) AlterItemTag(com.zimbra.cs.redolog.op.AlterItemTag) CreateTag(com.zimbra.cs.redolog.op.CreateTag) DbTag(com.zimbra.cs.db.DbTag) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) TypedIdList(com.zimbra.cs.mailbox.util.TypedIdList) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint)

Example 3 with TargetConstraint

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

the class Mailbox method moveInternal.

private void moveInternal(OperationContext octxt, int[] itemIds, MailItem.Type type, int targetId, TargetConstraint tcon) throws ServiceException {
    MoveItem redoRecorder = new MoveItem(mId, itemIds, type, targetId, tcon);
    boolean success = false;
    try {
        beginTransaction("move", octxt, redoRecorder);
        setOperationTargetConstraint(tcon);
        Folder target = getFolderById(targetId);
        MailItem[] items = getItemById(itemIds, type);
        for (MailItem item : items) {
            checkItemChangeID(item);
        }
        int oldUIDNEXT = target.getImapUIDNEXT();
        boolean resetUIDNEXT = false;
        for (MailItem item : items) {
            // train the spam filter if necessary...
            trainSpamFilter(octxt, item, target, "move");
            // ...do the move...
            boolean moved = item.move(target);
            // ...and determine whether the move needs to cause an UIDNEXT change
            if (moved && !resetUIDNEXT && isTrackingImap() && (item instanceof Conversation || item instanceof Message || item instanceof Contact)) {
                resetUIDNEXT = true;
            }
        }
        // if this operation should cause the target folder's UIDNEXT value to change but it hasn't yet, do it here
        if (resetUIDNEXT && oldUIDNEXT == target.getImapUIDNEXT()) {
            MoveItem redoPlayer = (MoveItem) currentChange().getRedoPlayer();
            redoRecorder.setUIDNEXT(getNextItemId(redoPlayer == null ? ID_AUTO_INCREMENT : redoPlayer.getUIDNEXT()));
            target.updateUIDNEXT();
        }
        success = true;
    } finally {
        endTransaction(success);
    }
}
Also used : DbMailItem(com.zimbra.cs.db.DbMailItem) ZimbraMailItem(com.zimbra.common.mailbox.ZimbraMailItem) ImapMessage(com.zimbra.cs.imap.ImapMessage) Pop3Message(com.zimbra.cs.pop3.Pop3Message) MimeMessage(javax.mail.internet.MimeMessage) CreateMessage(com.zimbra.cs.redolog.op.CreateMessage) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) MoveItem(com.zimbra.cs.redolog.op.MoveItem) CreateFolder(com.zimbra.cs.redolog.op.CreateFolder) ZFolder(com.zimbra.client.ZFolder) RefreshMountpoint(com.zimbra.cs.redolog.op.RefreshMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) CreateMountpoint(com.zimbra.cs.redolog.op.CreateMountpoint) ModifyContact(com.zimbra.cs.redolog.op.ModifyContact) ParsedContact(com.zimbra.cs.mime.ParsedContact) CreateContact(com.zimbra.cs.redolog.op.CreateContact)

Example 4 with TargetConstraint

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

the class AlterItemTag method redo.

@Override
public void redo() throws Exception {
    Mailbox mbox = MailboxManager.getInstance().getMailboxById(getMailboxId());
    OperationContext octxt = getOperationContext();
    TargetConstraint tcon = null;
    if (mConstraint != null) {
        try {
            tcon = TargetConstraint.parseConstraint(mbox, mConstraint);
        } catch (ServiceException e) {
            mLog.warn(e);
        }
    }
    if (mTagName == null && mTagId != 0) {
        mTagName = TagUtil.tagIdToName(mbox, octxt, mTagId);
    }
    mbox.alterTag(octxt, mIds, type, mTagName, mTagged, tcon);
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Mailbox(com.zimbra.cs.mailbox.Mailbox) ServiceException(com.zimbra.common.service.ServiceException) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint)

Example 5 with TargetConstraint

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

the class ItemActionHelper method MOVE.

/**
 * Account relative path conversation move.
 */
public static List<ItemActionHelper> MOVE(OperationContext octxt, Mailbox mbox, SoapProtocol responseProto, List<Integer> ids, TargetConstraint tcon, String acctRelativePath) throws ServiceException {
    List<ItemActionHelper> returnList = new ArrayList<>();
    // First build all external account / data source root folder ids
    Set<Integer> dsRootFolderIds = new HashSet<>();
    if (!ids.isEmpty()) {
        List<DataSource> dataSources = mbox.getAccount().getAllDataSources();
        if (dataSources != null) {
            for (DataSource ds : dataSources) {
                int dsFolderId = ds.getFolderId();
                if (dsFolderId != -1) {
                    dsRootFolderIds.add(dsFolderId);
                }
            }
        }
    }
    for (int convId : ids) {
        Integer rootFolderIdForConv = null;
        for (Message msg : mbox.getMessagesByConversation(octxt, convId, SortBy.NONE, -1)) {
            int rootFolderIdForThisMsg = AccountUtil.getRootFolderIdForItem(msg, mbox, dsRootFolderIds);
            if (rootFolderIdForConv == null) {
                rootFolderIdForConv = rootFolderIdForThisMsg;
            } else if (rootFolderIdForConv != rootFolderIdForThisMsg) {
                // this is conv spanning multiple accounts / data sources
                rootFolderIdForConv = null;
                break;
            }
        }
        if (rootFolderIdForConv == null) {
            continue;
        }
        Folder rootFolder = mbox.getFolderById(octxt, rootFolderIdForConv);
        String rootFolderPath = rootFolder.getPath();
        rootFolderPath = "/".equals(rootFolderPath) ? "" : rootFolderPath;
        String targetFolderPath = rootFolderPath.concat(acctRelativePath.startsWith("/") ? acctRelativePath : "/" + acctRelativePath);
        Folder targetFolder;
        try {
            targetFolder = mbox.getFolderByPath(octxt, targetFolderPath);
        } catch (MailServiceException.NoSuchItemException e) {
            targetFolder = mbox.createFolder(octxt, targetFolderPath, new Folder.FolderOptions().setDefaultView(MailItem.Type.MESSAGE));
        }
        returnList.add(MOVE(octxt, mbox, responseProto, Arrays.asList(convId), MailItem.Type.CONVERSATION, tcon, new ItemId(targetFolder)));
    }
    return returnList;
}
Also used : Message(com.zimbra.cs.mailbox.Message) MimeMessage(javax.mail.internet.MimeMessage) ArrayList(java.util.ArrayList) Folder(com.zimbra.cs.mailbox.Folder) ZFolder(com.zimbra.client.ZFolder) ItemId(com.zimbra.cs.service.util.ItemId) ZMountpoint(com.zimbra.client.ZMountpoint) TargetConstraint(com.zimbra.cs.mailbox.MailItem.TargetConstraint) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) DataSource(com.zimbra.cs.account.DataSource) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) HashSet(java.util.HashSet)

Aggregations

TargetConstraint (com.zimbra.cs.mailbox.MailItem.TargetConstraint)13 ServiceException (com.zimbra.common.service.ServiceException)6 Mailbox (com.zimbra.cs.mailbox.Mailbox)6 ZFolder (com.zimbra.client.ZFolder)5 ArrayList (java.util.ArrayList)5 ZimbraMailItem (com.zimbra.common.mailbox.ZimbraMailItem)4 DbMailItem (com.zimbra.cs.db.DbMailItem)4 OperationContext (com.zimbra.cs.mailbox.OperationContext)4 ItemId (com.zimbra.cs.service.util.ItemId)4 ZMailbox (com.zimbra.client.ZMailbox)3 Element (com.zimbra.common.soap.Element)3 Account (com.zimbra.cs.account.Account)3 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)3 CreateMountpoint (com.zimbra.cs.redolog.op.CreateMountpoint)3 RefreshMountpoint (com.zimbra.cs.redolog.op.RefreshMountpoint)3 HashMap (java.util.HashMap)3 ZMountpoint (com.zimbra.client.ZMountpoint)2 Color (com.zimbra.common.mailbox.Color)2 SoapProtocol (com.zimbra.common.soap.SoapProtocol)2 DbTag (com.zimbra.cs.db.DbTag)2