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();
}
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);
}
}
}
}
}
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;
}
Aggregations