use of com.zimbra.cs.mailbox.Tag in project zm-mailbox by Zimbra.
the class ImapHandler method doAPPEND.
boolean doAPPEND(String tag, ImapPath path, List<AppendMessage> appends) throws IOException, ImapException {
checkCommandThrottle(new AppendCommand(path, appends));
if (!checkState(tag, State.AUTHENTICATED)) {
return true;
}
Object mboxobj = null;
List<Tag> newTags = new ArrayList<Tag>();
List<Integer> createdIds = new ArrayList<Integer>(appends.size());
StringBuilder appendHint = extensionEnabled("UIDPLUS") ? new StringBuilder() : 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());
}
mboxobj = path.getOwnerMailbox();
Object folderobj = path.getFolder();
Mailbox mbox = mboxobj instanceof Mailbox ? (Mailbox) mboxobj : credentials.getMailbox();
mbox.lock.lock();
try {
ImapFlagCache flagset = ImapFlagCache.getSystemFlags(mbox);
ImapFlagCache tagset = mboxobj instanceof Mailbox ? new ImapFlagCache((Mailbox) mboxobj, getContext()) : new ImapFlagCache();
for (AppendMessage append : appends) {
append.checkFlags(mbox, flagset, tagset, newTags);
}
} finally {
mbox.lock.release();
}
// Append message parts and check message content size
for (AppendMessage append : appends) {
append.checkContent();
}
for (AppendMessage append : appends) {
int id = append.storeContent(mboxobj, folderobj);
if (id > 0) {
createdIds.add(id);
}
}
int uvv = (folderobj instanceof Folder ? ImapFolder.getUIDValidity((Folder) folderobj) : ImapFolder.getUIDValidity((ZFolder) folderobj));
if (appendHint != null && uvv > 0) {
appendHint.append("[APPENDUID ").append(uvv).append(' ').append(ImapFolder.encodeSubsequence(createdIds)).append("] ");
}
} catch (ServiceException e) {
for (AppendMessage append : appends) {
append.cleanup();
}
deleteTags(newTags);
deleteMessages(mboxobj, createdIds);
String msg = "APPEND failed";
if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
ZimbraLog.imap.info("APPEND failed: no such folder: " + path);
// of the text of the tagged NO response."
if (path.isCreatable()) {
msg = "[TRYCREATE] APPEND failed: no such mailbox";
}
} else if (e.getCode().equals(MailServiceException.INVALID_NAME)) {
ZimbraLog.imap.info("APPEND failed: " + e.getMessage());
} else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_VISIBLE)) {
ZimbraLog.imap.info("APPEND failed: folder not visible: " + path);
} else if (e.getCode().equals(ImapServiceException.FOLDER_NOT_WRITABLE)) {
ZimbraLog.imap.info("APPEND failed: folder not writable: " + path);
} else if (e.getCode().equals(MailServiceException.QUOTA_EXCEEDED)) {
ZimbraLog.imap.info("APPEND failed: quota exceeded");
} else {
ZimbraLog.imap.warn("APPEND failed", e);
}
sendNO(tag, msg);
return canContinue(e);
}
sendNotifications(true, false);
sendOK(tag, (appendHint == null ? "" : appendHint.toString()) + "APPEND completed");
return true;
}
use of com.zimbra.cs.mailbox.Tag in project zm-mailbox by Zimbra.
the class TestTags method cleanUp.
private void cleanUp() throws Exception {
Set<Integer> messageIds = search("subject:\"Test tags\"", MailItem.Type.MESSAGE);
for (int id : messageIds) {
mMbox.delete(null, id, MailItem.Type.MESSAGE);
}
List<Tag> tags = mMbox.getTagList(null);
if (tags == null) {
return;
}
for (Tag tag : tags) {
if (tag.getName().startsWith(TAG_PREFIX)) {
mMbox.delete(null, tag.getId(), tag.getType());
}
}
if (mountpoint != null) {
try {
mMbox.delete(null, mountpoint.getId(), MailItem.Type.MOUNTPOINT);
} catch (Exception e) {
}
mountpoint = null;
}
try {
TestUtil.deleteAccount(remoteUser);
} catch (Exception e) {
}
}
use of com.zimbra.cs.mailbox.Tag in project zm-mailbox by Zimbra.
the class Sync method deltaSync.
private static String deltaSync(Element response, OperationContext octxt, ItemIdFormatter ifmt, Mailbox mbox, SyncToken syncToken, int deleteLimit, int changeLimit, boolean typedDeletes, Folder root, Set<Folder> visible, int messageSyncStart) throws ServiceException {
int begin = syncToken.getChangeId();
int deleteModSeqCutoff = syncToken.getDeleteModSeq();
deleteModSeqCutoff = deleteModSeqCutoff <= 0 ? begin : deleteModSeqCutoff;
int mboxLastChangeId = mbox.getLastChangeID();
SyncToken newSyncToken = new SyncToken(mboxLastChangeId);
if (begin >= mboxLastChangeId && deleteModSeqCutoff >= mboxLastChangeId) {
return newSyncToken.toString();
}
int changeItemIdCutoff = syncToken.getOffsetInNext();
int deleteItemIdCutoff = syncToken.getDeleteOffsetInNext();
// first, fetch deleted items
TypedIdList tombstones = mbox.getTombstones(deleteModSeqCutoff);
Element eDeleted = response.addElement(MailConstants.E_DELETED);
// then, put together the requested folder hierarchy in 2 different flavors
List<Folder> hierarchy = (root == null || root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : root.getSubfolderHierarchy());
Set<Integer> targetIds = (root != null && root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : new HashSet<Integer>(hierarchy == null ? 0 : hierarchy.size()));
if (hierarchy != null) {
for (Folder folder : hierarchy) {
targetIds.add(folder.getId());
}
}
// then, handle created/modified folders
if (octxt.isDelegatedRequest(mbox)) {
// first, make sure that something changed...
if (!mbox.getModifiedFolders(begin).isEmpty() || !Collections.disjoint(tombstones.types(), FOLDER_TYPES)) {
// special-case the folder hierarchy for delegated delta sync
boolean anyFolders = folderSync(response, octxt, ifmt, mbox, root, visible, -1, messageSyncStart, SyncPhase.DELTA);
// if no folders are visible, add an empty "<folder/>" as a hint
if (!anyFolders) {
response.addElement(MailConstants.E_FOLDER);
}
}
} else {
for (Folder folder : mbox.getModifiedFolders(begin)) {
// no case of "synthetic tombstone" (item falling out of the tree being synced)
if (targetIds == null || targetIds.contains(folder.getId())) {
ToXML.encodeFolder(response, ifmt, octxt, folder, Change.ALL_FIELDS);
} else {
tombstones.add(folder.getType(), folder.getId(), folder.getUuid(), folder.getModifiedSequence());
}
}
}
// next, handle created/modified tags
for (Tag tag : mbox.getModifiedTags(octxt, begin)) {
ToXML.encodeTag(response, ifmt, octxt, tag, Change.ALL_FIELDS);
}
// finally, handle created/modified "other items"
int itemCount = 0;
Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, Math.min(begin, deleteModSeqCutoff), messageSyncStart, MailItem.Type.UNKNOWN, targetIds, deleteModSeqCutoff);
List<Integer> modified = changed.getFirst();
// items that have been altered in non-visible folders will be returned as "deleted" in order to handle moves
if (changed.getSecond() != null) {
tombstones.addAll(changed.getSecond());
}
delta: while (!modified.isEmpty()) {
List<Integer> batch = modified.subList(0, Math.min(modified.size(), FETCH_BATCH_SIZE));
for (MailItem item : mbox.getItemById(octxt, batch, MailItem.Type.UNKNOWN)) {
// detect interrupted sync and resume from the appropriate place
if ((item.getModifiedSequence() == begin + 1 && item.getId() < changeItemIdCutoff) || item.getModifiedSequence() <= begin) {
//if interrupted delete and un-interrupted modifications.
continue;
}
// if we've overflowed this sync response, set things up so that a subsequent sync starts from where we're cutting off
if (itemCount >= changeLimit) {
response.addAttribute(MailConstants.A_QUERY_MORE, true);
newSyncToken.setChangeModSeq((item.getModifiedSequence() - 1));
newSyncToken.setChangeItemId(item.getId());
newSyncToken.setDeleteModSeq(mboxLastChangeId);
break delta;
}
// For items in the system, if the content has changed since the user last sync'ed
// (because it was edited or created), just send back the folder ID and saved date --
// the client will request the whole object out of band -- potentially using the
// content servlet's "include metadata in headers" hack.
// If it's just the metadata that changed, send back the set of mutable attributes.
boolean created = item.getSavedSequence() > begin;
ToXML.encodeItem(response, ifmt, octxt, item, created ? Change.FOLDER | Change.CONFLICT | Change.DATE | Change.PARENT : MUTABLE_FIELDS);
itemCount++;
}
batch.clear();
}
// cleanup: only return a <deleted> element if we're sending back deleted item ids
if ((deleteLimit > 0 && tombstones.size() > deleteLimit) || deleteItemIdCutoff > 0) {
PagedDelete pgDel = new PagedDelete(tombstones, typedDeletes);
pgDel.removeBeforeCutoff(deleteItemIdCutoff, deleteModSeqCutoff);
if (deleteLimit > 0) {
pgDel.trimDeletesTillPageLimit(deleteLimit);
}
encodePagedDelete(eDeleted, pgDel, newSyncToken, tombstones, typedDeletes);
if (pgDel.isDeleteOverFlow()) {
response.addAttribute(MailConstants.A_QUERY_MORE, true);
response.addAttribute(MailConstants.A_QUERY_MORE, true);
}
} else {
encodeUnpagedDelete(eDeleted, tombstones, typedDeletes);
}
return newSyncToken.toString();
}
use of com.zimbra.cs.mailbox.Tag in project zm-mailbox by Zimbra.
the class TestConcurrency method testTag.
@Test
public void testTag() throws Exception {
int numThreads = 5;
Thread[] threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++) {
Tag tag = mMbox.createTag(null, TAG_PREFIX + i + 1, (byte) 0);
threads[i] = new Thread(new TagMessagesThread(tag, 5), "TagMessagesThread-" + i);
}
runThreads(threads);
}
use of com.zimbra.cs.mailbox.Tag in project zm-mailbox by Zimbra.
the class TestConcurrency method tearDown.
@After
public void tearDown() throws Exception {
// Delete tags - kept for testing purposes
List<Tag> tagList = mMbox.getTagList(null);
if (tagList != null) {
Iterator<Tag> i = tagList.iterator();
while (i.hasNext()) {
Tag tag = i.next();
if (tag.getName().startsWith(TAG_PREFIX)) {
mMbox.delete(null, tag.getId(), tag.getType());
}
}
}
// Move items from temp folder back to inbox
Folder folder = TestUtil.getFolderByPath(mMbox, FOLDER_NAME);
if (folder != null) {
List<MailItem> ids = mMbox.getItemList(null, MailItem.Type.MESSAGE, folder.getId());
Iterator<MailItem> i = ids.iterator();
while (i.hasNext()) {
Message message = (Message) i.next();
mMbox.move(null, message.getId(), MailItem.Type.MESSAGE, Mailbox.ID_FOLDER_INBOX);
}
mMbox.delete(null, folder.getId(), folder.getType());
}
cleanUp();
}
Aggregations