Search in sources :

Example 1 with ImapFlag

use of com.zimbra.cs.imap.ImapFlagCache.ImapFlag in project zm-mailbox by Zimbra.

the class ImapMessage method getFlags.

String getFlags(ImapFolder i4folder) {
    if ((flags & IMAP_FLAGS) == Flag.BITMASK_UNREAD && ArrayUtil.isEmpty(tags) && sflags == 0) {
        return NO_FLAGS;
    }
    StringBuilder result = new StringBuilder("FLAGS (");
    int empty = result.length();
    if ((flags & Flag.BITMASK_DELETED) != 0) {
        result.append(result.length() == empty ? "" : " ").append("\\Deleted");
    }
    if ((flags & Flag.BITMASK_DRAFT) != 0) {
        result.append(result.length() == empty ? "" : " ").append("\\Draft");
    }
    if ((flags & Flag.BITMASK_FLAGGED) != 0) {
        result.append(result.length() == empty ? "" : " ").append("\\Flagged");
    }
    if ((flags & Flag.BITMASK_REPLIED) != 0) {
        result.append(result.length() == empty ? "" : " ").append("\\Answered");
    }
    if ((flags & Flag.BITMASK_NOTIFIED) != 0) {
        result.append(result.length() == empty ? "" : " ").append("$MDNSent");
    }
    if ((flags & Flag.BITMASK_FORWARDED) != 0) {
        result.append(result.length() == empty ? "" : " ").append("$Forwarded Forwarded");
    }
    // note: \Seen is the IMAP flag, but we store "unread", so the test here is "== 0" not "!= 0"
    if ((flags & Flag.BITMASK_UNREAD) == 0) {
        result.append(result.length() == empty ? "" : " ").append("\\Seen");
    }
    if ((sflags & FLAG_RECENT) != 0) {
        result.append(result.length() == empty ? "" : " ").append("\\Recent");
    }
    if ((sflags & FLAG_SPAM) != 0) {
        result.append(result.length() == empty ? "" : " ").append("$Junk Junk");
    }
    if ((sflags & FLAG_NONSPAM) != 0) {
        result.append(result.length() == empty ? "" : " ").append("$NotJunk NotJunk NonJunk");
    }
    if ((sflags & FLAG_JUNKRECORDED) != 0) {
        result.append(result.length() == empty ? "" : " ").append("JunkRecorded");
    }
    ImapFlagCache i4cache = i4folder.getTagset();
    if (!ArrayUtil.isEmpty(tags)) {
        for (String tag : tags) {
            ImapFlag i4flag = i4cache.getByZimbraName(tag);
            if (i4flag != null) {
                // make sure there's no naming conflict with a system flag like "Forwarded" or "NonJunk"
                ImapFlag other = i4folder.getFlagByName(i4flag.mImapName);
                if (other == null || other == i4flag) {
                    result.append(result.length() == empty ? "" : " ").append(i4flag);
                }
            } else {
                // this is not a visible tag; perform the conflict check and return anyways
                ImapFlag other = i4folder.getFlagByName(tag);
                if (other == null) {
                    result.append(result.length() == empty ? "" : " ").append(tag);
                }
            }
        }
    }
    return result.append(')').toString();
}
Also used : ImapFlag(com.zimbra.cs.imap.ImapFlagCache.ImapFlag)

Example 2 with ImapFlag

use of com.zimbra.cs.imap.ImapFlagCache.ImapFlag in project zm-mailbox by Zimbra.

the class ImapFolder method updateTagCache.

protected void updateTagCache(ImapMessage i4msg) {
    if (!ArrayUtil.isEmpty(i4msg.tags)) {
        for (String tag : i4msg.tags) {
            if (tags.getByZimbraName(tag) == null) {
                try {
                    ImapFlag flag = mailboxStore.getTagByName(tag);
                    if (flag != null) {
                        // null means that the tag was changed while the folder was paged out
                        tags.cache(flag);
                        setTagsDirty(true);
                    }
                } catch (ServiceException e) {
                    ZimbraLog.imap.warn("could not fetch listed tag: %s", tag, e);
                }
            }
        }
    }
}
Also used : ImapFlag(com.zimbra.cs.imap.ImapFlagCache.ImapFlag) ServiceException(com.zimbra.common.service.ServiceException)

Example 3 with ImapFlag

use of com.zimbra.cs.imap.ImapFlagCache.ImapFlag in project zm-mailbox by Zimbra.

the class ImapHandler method doSTORE.

private boolean doSTORE(String tag, String sequenceSet, List<String> flagNames, StoreAction operation, boolean silent, int modseq, boolean byUID) throws IOException, ImapException {
    checkCommandThrottle(new StoreCommand(sequenceSet, flagNames, operation, modseq));
    if (!checkState(tag, State.SELECTED)) {
        return true;
    }
    ImapFolder i4folder = getSelectedFolder();
    if (i4folder == null) {
        throw new ImapSessionClosedException();
    }
    if (!i4folder.isWritable()) {
        sendNO(tag, "mailbox selected READ-ONLY");
        return true;
    }
    if (modseq >= 0) {
        activateExtension(ImapExtension.CONDSTORE);
    }
    boolean modseqEnabled = sessionActivated(ImapExtension.CONDSTORE);
    // MUST reject any such command with the tagged BAD response."
    if (!modseqEnabled && modseq >= 0) {
        throw new ImapParseException(tag, "NOMODSEQ", "cannot STORE UNCHANGEDSINCE in this mailbox", true);
    }
    ImapMessageSet modifyConflicts = modseqEnabled ? new ImapMessageSet() : null;
    String command = (byUID ? "UID STORE" : "STORE");
    List<Tag> newTags = (operation != StoreAction.REMOVE ? new ArrayList<Tag>() : null);
    MailboxStore mbox = selectedFolderListener.getMailbox();
    Set<ImapMessage> i4set;
    mbox.lock(true);
    try {
        i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
    } finally {
        mbox.unlock();
    }
    boolean allPresent = byUID || !i4set.contains(null);
    i4set.remove(null);
    try {
        // list of tag names (not including Flags)
        List<String> tags = Lists.newArrayList();
        // just Flag objects, no need to convert Tag objects to ImapFlag here
        Set<ImapFlag> i4flags = new HashSet<ImapFlag>(flagNames.size());
        for (String name : flagNames) {
            ImapFlag i4flag = i4folder.getFlagByName(name);
            if (i4flag == null) {
                tags.add(name);
                // new tag for this folder
                continue;
            } else if (i4flag.mId > 0) {
                tags.add(i4flag.mName);
            } else {
                i4flags.add(i4flag);
            }
            if (operation != StoreAction.REMOVE) {
                if (i4flag.mId == Flag.ID_DELETED) {
                    if (!i4folder.getPath().isWritable(ACL.RIGHT_DELETE)) {
                        throw ServiceException.PERM_DENIED("you do not have permission to set the \\Deleted flag");
                    }
                } else if (i4flag.mPermanent && (!i4folder.getPath().isWritable(ACL.RIGHT_WRITE))) {
                    throw ServiceException.PERM_DENIED("you do not have permission to set the " + i4flag.mName + " flag");
                }
            }
        }
        // if we're doing a STORE FLAGS (i.e. replace), precompute the new set of flags for all the affected messages
        int flags = Flag.BITMASK_UNREAD;
        short sflags = 0;
        if (operation == StoreAction.REPLACE) {
            for (ImapFlag i4flag : i4flags) {
                if (!i4flag.mPermanent) {
                    sflags = (byte) (i4flag.mPositive ? sflags | i4flag.mBitmask : sflags & ~i4flag.mBitmask);
                } else {
                    flags = (int) (i4flag.mPositive ? flags | i4flag.mBitmask : flags & ~i4flag.mBitmask);
                }
            }
        }
        long checkpoint = System.currentTimeMillis();
        int i = 0;
        List<ImapMessage> i4list = new ArrayList<ImapMessage>(SUGGESTED_BATCH_SIZE);
        List<Integer> idlist = new ArrayList<Integer>(SUGGESTED_BATCH_SIZE);
        for (ImapMessage msg : i4set) {
            // we're sending 'em off in batches of 100
            i4list.add(msg);
            idlist.add(msg.msgId);
            if (++i % SUGGESTED_BATCH_SIZE != 0 && i != i4set.size()) {
                continue;
            }
            mbox.lock(true);
            try {
                String folderOwner = i4folder.getFolder().getFolderItemIdentifier().accountId;
                List<ItemIdentifier> itemIds = ItemIdentifier.fromAccountIdAndItemIds((folderOwner != null) ? folderOwner : mbox.getAccountId(), idlist);
                if (modseq >= 0) {
                    List<ZimbraMailItem> items = mbox.getItemsById(getContext(), itemIds);
                    for (int idx = items.size() - 1; idx >= 0; idx--) {
                        ImapMessage i4msg = i4list.get(idx);
                        if (items.get(idx).getModifiedSequence() > modseq) {
                            modifyConflicts.add(i4msg);
                            i4list.remove(idx);
                            idlist.remove(idx);
                            allPresent = false;
                        }
                    }
                }
                try {
                    // if it was a STORE [+-]?FLAGS.SILENT, temporarily disable notifications
                    if (silent && !modseqEnabled) {
                        i4folder.disableNotifications();
                    }
                    if (operation == StoreAction.REPLACE) {
                        // replace real tags and flags on all messages
                        mbox.setTags(getContext(), itemIds, flags, tags);
                        // replace session tags on all messages
                        for (ImapMessage i4msg : i4list) {
                            i4msg.setSessionFlags(sflags, i4folder);
                        }
                    } else {
                        for (ImapFlag i4flag : i4flags) {
                            boolean add = operation == StoreAction.ADD ^ !i4flag.mPositive;
                            if (i4flag.mPermanent) {
                                // real Flag (not a Tag); do a batch update to the DB
                                if ((i4flag.mBitmask & Flag.BITMASK_DELETED) > 0) {
                                    ZimbraLog.imap.info("IMAP client has flagged the item with id %d to be Deleted altertag", msg.msgId);
                                }
                                mbox.alterTag(getContext(), itemIds, i4flag.mName, add);
                            } else {
                                // session tag; update one-by-one in memory only
                                for (ImapMessage i4msg : i4list) {
                                    i4msg.setSessionFlags((short) (add ? i4msg.sflags | i4flag.mBitmask : i4msg.sflags & ~i4flag.mBitmask), i4folder);
                                }
                            }
                        }
                        boolean add = operation == StoreAction.ADD;
                        // add (or remove) Tags
                        for (String tagName : tags) {
                            mbox.alterTag(getContext(), itemIds, tagName, add);
                        }
                    }
                } finally {
                    // if it was a STORE [+-]?FLAGS.SILENT, reenable notifications
                    i4folder.enableNotifications();
                }
            } finally {
                mbox.unlock();
            }
            if (!silent || modseqEnabled) {
                for (ImapMessage i4msg : i4list) {
                    ImapFolder.DirtyMessage dirty = i4folder.undirtyMessage(i4msg);
                    if (silent && (dirty == null || dirty.modseq <= 0)) {
                        continue;
                    }
                    StringBuilder ntfn = new StringBuilder();
                    boolean empty = true;
                    ntfn.append(i4msg.sequence).append(" FETCH (");
                    if (!silent) {
                        ntfn.append(i4msg.getFlags(i4folder));
                        empty = false;
                    }
                    // caused by a UID command..."
                    if (byUID) {
                        ntfn.append(empty ? "" : " ").append("UID ").append(i4msg.imapUid);
                        empty = false;
                    }
                    if (dirty != null && dirty.modseq > 0 && modseqEnabled) {
                        ntfn.append(empty ? "" : " ").append("MODSEQ (").append(dirty.modseq).append(')');
                        empty = false;
                    }
                    sendUntagged(ntfn.append(')').toString());
                }
            } else {
                // 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;
                }
            }
            i4list.clear();
            idlist.clear();
        }
    } catch (ServiceException e) {
        deleteTags(newTags);
        if (e.getCode().equals(MailServiceException.INVALID_NAME)) {
            ZimbraLog.imap.info("%s failed: %s", command, e.getMessage());
        } else {
            ZimbraLog.imap.warn("%s failed", command, e);
        }
        sendNO(tag, command + " failed");
        return canContinue(e);
    }
    boolean hadConflicts = modifyConflicts != null && !modifyConflicts.isEmpty();
    String conflicts = hadConflicts ? " [MODIFIED " + ImapFolder.encodeSubsequence(modifyConflicts, byUID) + ']' : "";
    sendNotifications(byUID, false);
    // a FETCH response for the non-expunged messages along with a tagged NO."
    if (silent || allPresent) {
        sendOK(tag, command + conflicts + " completed");
    } else {
        sendNO(tag, command + conflicts + " completed");
    }
    return true;
}
Also used : MailboxStore(com.zimbra.common.mailbox.MailboxStore) ArrayList(java.util.ArrayList) ItemIdentifier(com.zimbra.common.mailbox.ItemIdentifier) ZimbraMailItem(com.zimbra.common.mailbox.ZimbraMailItem) ImapMessageSet(com.zimbra.cs.imap.ImapMessage.ImapMessageSet) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet) ImapFlag(com.zimbra.cs.imap.ImapFlagCache.ImapFlag) AccountServiceException(com.zimbra.cs.account.AccountServiceException) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) Tag(com.zimbra.cs.mailbox.Tag)

Aggregations

ImapFlag (com.zimbra.cs.imap.ImapFlagCache.ImapFlag)3 ServiceException (com.zimbra.common.service.ServiceException)2 ItemIdentifier (com.zimbra.common.mailbox.ItemIdentifier)1 MailboxStore (com.zimbra.common.mailbox.MailboxStore)1 ZimbraMailItem (com.zimbra.common.mailbox.ZimbraMailItem)1 AccountServiceException (com.zimbra.cs.account.AccountServiceException)1 ImapMessageSet (com.zimbra.cs.imap.ImapMessage.ImapMessageSet)1 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)1 Tag (com.zimbra.cs.mailbox.Tag)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1