Search in sources :

Example 1 with ItemActionHelper

use of com.zimbra.cs.service.mail.ItemActionHelper in project zm-mailbox by Zimbra.

the class ImapHandler method doCOPY.

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 = "";
    List<MailItem> copies = new ArrayList<MailItem>();
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    Mailbox mbox = i4folder.getMailbox();
    Set<ImapMessage> i4set;
    mbox.lock.lock();
    try {
        i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
    } finally {
        mbox.lock.release();
    }
    //                  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());
        }
        Object mboxobj = path.getOwnerMailbox();
        ItemId iidTarget;
        boolean sameMailbox = false;
        int uvv;
        // check target folder permissions before attempting the copy
        if (mboxobj instanceof Mailbox) {
            sameMailbox = mbox.getAccountId().equalsIgnoreCase(((Mailbox) mboxobj).getAccountId());
            Folder folder = (Folder) path.getFolder();
            iidTarget = new ItemId(folder);
            uvv = ImapFolder.getUIDValidity(folder);
        } else if (mboxobj instanceof ZMailbox) {
            ZFolder zfolder = (ZFolder) path.getFolder();
            iidTarget = new ItemId(zfolder.getId(), path.getOwnerAccount().getId());
            uvv = ImapFolder.getUIDValidity(zfolder);
        } else {
            throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
        }
        long checkpoint = System.currentTimeMillis();
        List<Integer> srcUIDs = extensionEnabled("UIDPLUS") ? new ArrayList<Integer>() : null;
        List<Integer> copyUIDs = extensionEnabled("UIDPLUS") ? new ArrayList<Integer>() : null;
        int i = 0;
        List<ImapMessage> i4list = new ArrayList<ImapMessage>(SUGGESTED_COPY_BATCH_SIZE);
        List<Integer> idlist = new ArrayList<Integer>(SUGGESTED_COPY_BATCH_SIZE);
        List<Integer> createdList = new ArrayList<Integer>(SUGGESTED_COPY_BATCH_SIZE);
        for (ImapMessage i4msg : i4set) {
            // we're sending 'em off in batches of 50
            i4list.add(i4msg);
            idlist.add(i4msg.msgId);
            if (++i % SUGGESTED_COPY_BATCH_SIZE != 0 && i != i4set.size()) {
                continue;
            }
            if (sameMailbox) {
                List<MailItem> copyMsgs;
                try {
                    MailItem.Type type = MailItem.Type.UNKNOWN;
                    int[] mItemIds = new int[i4list.size()];
                    int counter = 0;
                    for (ImapMessage curMsg : i4list) {
                        mItemIds[counter++] = curMsg.msgId;
                        if (counter == 1) {
                            type = curMsg.getType();
                        } else if (curMsg.getType() != type) {
                            type = MailItem.Type.UNKNOWN;
                        }
                    }
                    copyMsgs = mbox.imapCopy(getContext(), mItemIds, type, iidTarget.getId());
                } catch (IOException e) {
                    throw ServiceException.FAILURE("Caught IOException executing " + this, e);
                }
                copies.addAll(copyMsgs);
                for (MailItem target : copyMsgs) {
                    createdList.add(target.getImapUid());
                }
            } else {
                ItemActionHelper op = ItemActionHelper.COPY(getContext(), mbox, null, idlist, MailItem.Type.UNKNOWN, null, iidTarget);
                for (String target : op.getCreatedIds()) {
                    createdList.add(new ItemId(target, selectedFolder.getAuthenticatedAccountId()).getId());
                }
            }
            if (createdList.size() != i4list.size()) {
                throw ServiceException.FAILURE("mismatch between original and target count during IMAP COPY", null);
            }
            if (srcUIDs != null) {
                for (ImapMessage source : i4list) {
                    srcUIDs.add(source.imapUid);
                }
                for (Integer target : createdList) {
                    copyUIDs.add(target);
                }
            }
            i4list.clear();
            idlist.clear();
            createdList.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 (uvv > 0 && srcUIDs != null && srcUIDs.size() > 0) {
            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 : ArrayList(java.util.ArrayList) SearchFolder(com.zimbra.cs.mailbox.SearchFolder) Folder(com.zimbra.cs.mailbox.Folder) ZFolder(com.zimbra.client.ZFolder) ItemId(com.zimbra.cs.service.util.ItemId) ZMailbox(com.zimbra.client.ZMailbox) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZMailbox(com.zimbra.client.ZMailbox) ZFolder(com.zimbra.client.ZFolder) IOException(java.io.IOException) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) MailItem(com.zimbra.cs.mailbox.MailItem) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) ItemActionHelper(com.zimbra.cs.service.mail.ItemActionHelper)

Aggregations

ZFolder (com.zimbra.client.ZFolder)1 ZMailbox (com.zimbra.client.ZMailbox)1 ServiceException (com.zimbra.common.service.ServiceException)1 AccountServiceException (com.zimbra.cs.account.AccountServiceException)1 Folder (com.zimbra.cs.mailbox.Folder)1 MailItem (com.zimbra.cs.mailbox.MailItem)1 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)1 Mailbox (com.zimbra.cs.mailbox.Mailbox)1 Mountpoint (com.zimbra.cs.mailbox.Mountpoint)1 SearchFolder (com.zimbra.cs.mailbox.SearchFolder)1 ItemActionHelper (com.zimbra.cs.service.mail.ItemActionHelper)1 ItemId (com.zimbra.cs.service.util.ItemId)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1