use of com.zimbra.cs.mailbox.util.TypedIdList in project zm-mailbox by Zimbra.
the class SearchActionTest method testSearchActionRead.
@Test
public void testSearchActionRead() throws Exception {
Account acct = Provisioning.getInstance().getAccountByName("testRead@zimbra.com");
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct);
// Add two messages to inbox, one with search match and other with no match
DeliveryOptions dopt = new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX).setFlags(Flag.BITMASK_UNREAD | Flag.BITMASK_MUTED);
Message message1 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), dopt, null);
Message message2 = mbox.addMessage(null, MailboxTestUtil.generateMessage("unmatched subject"), dopt, null);
TypedIdList ids = mbox.getItemIds(null, 2);
Assert.assertEquals(2, ids.size());
Assert.assertEquals(true, message1.isUnread());
Assert.assertEquals(true, message2.isUnread());
SearchRequest sRequest = new SearchRequest();
sRequest.setSearchTypes("conversation");
// search with query 'test'
sRequest.setQuery("test");
BulkAction bAction = new BulkAction();
// search action - mark search result with 'read'
bAction.setOp(BulkAction.Operation.read);
Map<String, Object> context = ServiceTestUtil.getRequestContext(acct);
ZimbraSoapContext zsc = (ZimbraSoapContext) context.get(SoapEngine.ZIMBRA_CONTEXT);
Element searchResponse = new Search().handle(zsc.jaxbToElement(sRequest), ServiceTestUtil.getRequestContext(acct));
com.zimbra.soap.mail.message.SearchResponse sResponse = zsc.elementToJaxb(searchResponse);
List<SearchHit> searchHits = sResponse.getSearchHits();
ConvActionRequest req = SearchAction.getConvActionRequest(searchHits, "read");
ConvAction convAction = new ConvAction();
PowerMockito.stub(PowerMockito.method(SoapHttpTransport.class, "invokeWithoutSession")).toReturn(convAction.handle(zsc.jaxbToElement(req), ServiceTestUtil.getRequestContext(acct)));
SearchAction.performAction(bAction, sRequest, searchHits, mbox, null);
// check search result message is marked read
Assert.assertEquals(false, message1.isUnread());
Assert.assertEquals(true, message2.isUnread());
}
use of com.zimbra.cs.mailbox.util.TypedIdList in project zm-mailbox by Zimbra.
the class Mailbox method purgeMessages.
/**
* Purges messages in system folders based on user- and admin-level purge settings on the account.
* Returns {@code true} if all messages that meet the purge criteria were purged, {@code false} if the number of
* messages to purge in any folder exceeded {@code maxItemsPerFolder}.
*/
public boolean purgeMessages(OperationContext octxt) throws ServiceException {
Account acct = getAccount();
int maxItemsPerFolder = Provisioning.getInstance().getLocalServer().getMailPurgeBatchSize();
if (ZimbraLog.purge.isDebugEnabled()) {
ZimbraLog.purge.debug("System retention policy: Trash=%s, Junk=%s, All messages=%s, Dumpster=%s", acct.getMailTrashLifetimeAsString(), acct.getMailSpamLifetimeAsString(), acct.getMailMessageLifetimeAsString(), acct.getMailDumpsterLifetimeAsString());
ZimbraLog.purge.debug("User-specified retention policy: Inbox read=%s, Inbox unread=%s, Sent=%s, Junk=%s, Trash=%s, Versions=%s, VersionsEnabled=%s", acct.getPrefInboxReadLifetimeAsString(), acct.getPrefInboxUnreadLifetimeAsString(), acct.getPrefSentLifetimeAsString(), acct.getPrefJunkLifetimeAsString(), acct.getPrefTrashLifetimeAsString(), acct.getFileVersionLifetimeAsString(), acct.isFileVersioningEnabled());
}
long globalTimeout = acct.getMailMessageLifetime();
long systemTrashTimeout = acct.getMailTrashLifetime();
long systemJunkTimeout = acct.getMailSpamLifetime();
boolean dumpsterPurgeEnabled = acct.isDumpsterPurgeEnabled();
long systemDumpsterTimeoutMillis = dumpsterPurgeEnabled ? acct.getMailDumpsterLifetime() : 0;
long userInboxReadTimeout = acct.getPrefInboxReadLifetime();
long userInboxUnreadTimeout = acct.getPrefInboxUnreadLifetime();
long userTrashTimeout = acct.getPrefTrashLifetime();
long userJunkTimeout = acct.getPrefJunkLifetime();
long userSentTimeout = acct.getPrefSentLifetime();
long trashTimeout = pickTimeout(systemTrashTimeout, userTrashTimeout);
long spamTimeout = pickTimeout(systemJunkTimeout, userJunkTimeout);
boolean userFileVersioningEnabled = acct.isFileVersioningEnabled();
long userFileVersionLifeTime = acct.getFileVersionLifetime();
if (globalTimeout <= 0 && trashTimeout <= 0 && spamTimeout <= 0 && userInboxReadTimeout <= 0 && userInboxReadTimeout <= 0 && userInboxUnreadTimeout <= 0 && userSentTimeout <= 0 && systemDumpsterTimeoutMillis <= 0 && (!userFileVersioningEnabled || userFileVersionLifeTime <= 0)) {
ZimbraLog.purge.debug("Retention policy does not require purge.");
return true;
}
ZimbraLog.purge.info("Purging messages.");
// sanity-check the really dangerous value...
if (globalTimeout > 0 && globalTimeout < Constants.MILLIS_PER_MONTH) {
// this min is also used by POP3 EXPIRE command. update Pop3Handler.MIN_EPXIRE_DAYS if it changes.
ZimbraLog.purge.warn("global message timeout < 1 month; defaulting to 31 days");
globalTimeout = Constants.MILLIS_PER_MONTH;
}
// call to purge expired messages with IMAP \Deleted flag
// for expiration check, used zimbraMailTrashLifetime
purgeExpiredIMAPDeletedMessages(trashTimeout);
PurgeOldMessages redoRecorder = new PurgeOldMessages(mId);
boolean success = false;
try {
beginTransaction("purgeMessages", octxt, redoRecorder);
// get the folders we're going to be purging
Folder trash = getFolderById(ID_FOLDER_TRASH);
Folder spam = getFolderById(ID_FOLDER_SPAM);
Folder sent = getFolderById(ID_FOLDER_SENT);
Folder inbox = getFolderById(ID_FOLDER_INBOX);
boolean purgedAll = true;
if (globalTimeout > 0) {
int numPurged = Folder.purgeMessages(this, null, getOperationTimestampMillis() - globalTimeout, null, false, false, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d messages from All Folders", numPurged);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
}
if (trashTimeout > 0) {
boolean useChangeDate = acct.getBooleanAttr(Provisioning.A_zimbraMailPurgeUseChangeDateForTrash, true);
int numPurged = Folder.purgeMessages(this, trash, getOperationTimestampMillis() - trashTimeout, null, useChangeDate, true, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d messages from Trash", numPurged);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
}
if (spamTimeout > 0) {
boolean useChangeDate = acct.isMailPurgeUseChangeDateForSpam();
int numPurged = Folder.purgeMessages(this, spam, getOperationTimestampMillis() - spamTimeout, null, useChangeDate, false, maxItemsPerFolder);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d messages from Spam", numPurged);
}
if (userInboxReadTimeout > 0) {
int numPurged = Folder.purgeMessages(this, inbox, getOperationTimestampMillis() - userInboxReadTimeout, false, false, false, maxItemsPerFolder);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d read messages from Inbox", numPurged);
}
if (userInboxUnreadTimeout > 0) {
int numPurged = Folder.purgeMessages(this, inbox, getOperationTimestampMillis() - userInboxUnreadTimeout, true, false, false, maxItemsPerFolder);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d unread messages from Inbox", numPurged);
}
if (userSentTimeout > 0) {
int numPurged = Folder.purgeMessages(this, sent, getOperationTimestampMillis() - userSentTimeout, null, false, false, maxItemsPerFolder);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d messages from Sent", numPurged);
}
if (systemDumpsterTimeoutMillis > 0) {
int numPurged = purgeDumpster(getOperationTimestampMillis() - systemDumpsterTimeoutMillis, maxItemsPerFolder);
ZimbraLog.purge.debug("Purged %d messages from Dumpster", numPurged);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
}
if (userFileVersioningEnabled && userFileVersionLifeTime > 0) {
int numPurged = MailItem.purgeRevisions(this, getOperationTimestampMillis() - userFileVersionLifeTime);
ZimbraLog.purge.debug("Purged %d revisions", numPurged);
}
// Process any folders that have retention policy set.
for (Folder folder : getFolderList(octxt, SortBy.NONE)) {
RetentionPolicy rp = RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(acct, folder.getRetentionPolicy());
for (Policy policy : rp.getPurgePolicy()) {
long folderLifetime;
try {
folderLifetime = DateUtil.getTimeInterval(policy.getLifetime());
} catch (ServiceException e) {
ZimbraLog.purge.error("Invalid purge lifetime set for folder %s.", folder.getPath(), e);
continue;
}
long folderTimeout = getOperationTimestampMillis() - folderLifetime;
int numPurged = Folder.purgeMessages(this, folder, folderTimeout, null, false, false, maxItemsPerFolder);
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
}
}
// Process any tags that have retention policy set.
for (Tag tag : getTagList(octxt)) {
RetentionPolicy rp = RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(acct, tag.getRetentionPolicy());
for (Policy policy : rp.getPurgePolicy()) {
long tagLifetime;
try {
tagLifetime = DateUtil.getTimeInterval(policy.getLifetime());
} catch (ServiceException e) {
ZimbraLog.purge.error("Invalid purge lifetime set for tag %s.", tag.getName(), e);
continue;
}
long tagTimeout = getOperationTimestampMillis() - tagLifetime;
PendingDelete info = DbTag.getLeafNodes(this, tag, (int) (tagTimeout / 1000), maxItemsPerFolder);
MailItem.delete(this, info, null, false, false);
List<Integer> ids = info.itemIds.getIds(MailItem.Type.MESSAGE);
int numPurged = (ids == null ? 0 : ids.size());
purgedAll = updatePurgedAll(purgedAll, numPurged, maxItemsPerFolder);
}
}
// deletes have already been collected, so fetch the tombstones and write once
TypedIdList tombstones = collectPendingTombstones();
if (tombstones != null && !tombstones.isEmpty()) {
DbMailItem.writeTombstones(this, tombstones);
}
if (Threader.isHashPurgeAllowed(acct)) {
int convTimeoutSecs = (int) (LC.conversation_max_age_ms.longValue() / Constants.MILLIS_PER_SECOND);
DbMailItem.closeOldConversations(this, getOperationTimestamp() - convTimeoutSecs);
}
if (isTrackingSync()) {
int tombstoneTimeoutSecs = (int) (LC.tombstone_max_age_ms.longValue() / Constants.MILLIS_PER_SECOND);
int largestTrimmed = DbMailItem.purgeTombstones(this, getOperationTimestamp() - tombstoneTimeoutSecs);
if (largestTrimmed > getSyncCutoff()) {
currentChange().sync = largestTrimmed;
DbMailbox.setSyncCutoff(this, currentChange().sync);
}
}
// record the purge time.
if (purgedAll) {
DbMailbox.updateLastPurgeAt(this, System.currentTimeMillis());
}
success = true;
ZimbraLog.purge.debug("purgedAll=%b", purgedAll);
return purgedAll;
} finally {
endTransaction(success);
}
}
use of com.zimbra.cs.mailbox.util.TypedIdList in project zm-mailbox by Zimbra.
the class PagedDeleteTest method testRemoveBeforeAfterCutoff.
@Test
public void testRemoveBeforeAfterCutoff() {
TypedIdList tombstone = new TypedIdList();
tombstone.add(Type.MESSAGE, 3, "", 100);
tombstone.add(Type.MESSAGE, 4, "", 101);
tombstone.add(Type.APPOINTMENT, 1, "", 101);
tombstone.add(Type.APPOINTMENT, 5, "", 100);
tombstone.add(Type.APPOINTMENT, 9, "", 103);
tombstone.add(Type.MESSAGE, 2, "", 99);
tombstone.add(Type.MESSAGE, 22, "", 105);
tombstone.add(Type.MESSAGE, 24, "", 103);
tombstone.add(Type.MESSAGE, 28, "", 106);
PagedDelete pgDelete = new PagedDelete(tombstone, true);
pgDelete.removeBeforeCutoff(4, 101);
Collection<Integer> ids = pgDelete.getAllIds();
Assert.assertEquals(5, ids.size());
pgDelete.trimDeletesTillPageLimit(5);
ids = pgDelete.getAllIds();
Assert.assertEquals(5, ids.size());
pgDelete.removeAfterCutoff(105);
ids = pgDelete.getAllIds();
Assert.assertEquals(4, ids.size());
Assert.assertTrue(ids.contains(4));
Assert.assertTrue(ids.contains(9));
Assert.assertTrue(ids.contains(24));
Assert.assertTrue(ids.contains(22));
Assert.assertTrue(pgDelete.isDeleteOverFlow());
Assert.assertEquals(pgDelete.getCutOffModsequnce(), 106);
Assert.assertEquals(pgDelete.getLastItemId(), 28);
Multimap<Type, Integer> ids2Type = pgDelete.getTypedItemIds();
Assert.assertEquals(4, ids2Type.size());
Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 4));
Assert.assertTrue(ids2Type.containsEntry(Type.APPOINTMENT, 9));
Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 24));
Assert.assertTrue(ids2Type.containsEntry(Type.MESSAGE, 22));
}
use of com.zimbra.cs.mailbox.util.TypedIdList in project zm-mailbox by Zimbra.
the class GalSearchControl method doLocalGalAccountSync.
private void doLocalGalAccountSync(Account galAcct) throws ServiceException {
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(galAcct);
OperationContext octxt = new OperationContext(mbox);
GalSearchResultCallback callback = mParams.getResultCallback();
Domain domain = mParams.getDomain();
GalMode galMode = domain.getGalMode();
int changeId = mParams.getGalSyncToken().getChangeId(galAcct.getId());
// bug 46608
// sync local resources from first datasource if galMode is ldap
// and zimbraGalAlwaysIncludeLocalCalendarResources is set for the domain
boolean syncLocalResources = (galMode == GalMode.ldap && domain.isGalAlwaysIncludeLocalCalendarResources());
Set<Integer> folderIds = new HashSet<Integer>();
String syncToken = null;
for (DataSource ds : galAcct.getAllDataSources()) {
if (ds.getType() != DataSourceType.gal) {
ZimbraLog.gal.trace("skipping datasource %s: wrong type %s expected %s", ds.getName(), ds.getType(), DataSourceType.gal);
continue;
}
if (galMode != null) {
if (!(galMode.isBoth() || galMode.toString().equals(ds.getAttr(Provisioning.A_zimbraGalType)))) {
ZimbraLog.gal.debug("skipping datasource %s: wrong zimbraGalType %s expected %s", ds.getName(), ds.getAttr(Provisioning.A_zimbraGalType), galMode.toString());
continue;
}
}
int fid = ds.getFolderId();
DataSourceItem folderMapping = DbDataSource.getMapping(ds, fid);
if (folderMapping.md == null) {
ZimbraLog.gal.debug("skipping datasource %s: no folder mapping", ds.getName());
continue;
}
folderIds.add(fid);
syncToken = LdapUtil.getEarlierTimestamp(syncToken, folderMapping.md.get(GalImport.SYNCTOKEN));
if (syncLocalResources) {
doLocalGalAccountSync(callback, mbox, octxt, changeId, folderIds, syncToken, mParams.getLimit(), Provisioning.A_zimbraAccountCalendarUserType, "RESOURCE", mParams.isGetCount());
syncLocalResources = false;
}
}
if (folderIds.isEmpty()) {
throw ServiceException.FAILURE("no gal datasource with mapped folder found", null);
}
if (syncToken == null) {
throw ServiceException.FAILURE("no gal datasource with sync token found", null);
}
doLocalGalAccountSync(callback, mbox, octxt, changeId, folderIds, syncToken, mParams.getLimit(), mParams.isGetCount());
List<Integer> deleted = null;
if (callback.getResponse() != null && !callback.getResponse().getAttributeBool(MailConstants.A_QUERY_MORE) && changeId > 0) {
try {
TypedIdList tIdList = mbox.getTombstones(changeId);
deleted = tIdList.getAllIds();
int deletedChangeId = tIdList.getMaxModSequence();
ZimbraLog.gal.debug("deleted change id = %s", deletedChangeId);
if (deletedChangeId > changeId) {
GalSyncToken newToken = new GalSyncToken(syncToken, mbox.getAccountId(), deletedChangeId);
ZimbraLog.gal.debug("computing new sync token for %s:%s", mbox.getAccountId(), newToken);
callback.setNewToken(newToken);
}
} catch (MailServiceException e) {
if (MailServiceException.MUST_RESYNC == e.getCode()) {
ZimbraLog.gal.warn("sync token too old, deleted items will not be handled", e);
} else {
throw e;
}
}
}
if (deleted != null) {
for (int itemId : deleted) {
callback.handleDeleted(new ItemId(galAcct.getId(), itemId));
}
}
}
use of com.zimbra.cs.mailbox.util.TypedIdList in project zm-mailbox by Zimbra.
the class GalSearchControl method doLocalGalAccountSync.
private void doLocalGalAccountSync(GalSearchResultCallback callback, Mailbox mbox, OperationContext octxt, int changeId, Set<Integer> folderIds, String syncToken, int limit, String filterAttr, String filterValue, boolean getCount) throws ServiceException {
ZimbraLog.gal.info("Using limit %d for gal account sync", limit);
Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, changeId, 0, MailItem.Type.CONTACT, folderIds, -1, limit);
if (getCount) {
int remain = 0;
if (limit != 0) {
int total = mbox.getModifiedItemsCount(octxt, changeId, 0, MailItem.Type.CONTACT, folderIds);
remain = total > limit ? total - limit : 0;
ZimbraLog.gal.debug("totalCount: %d", total);
}
callback.setRemain(remain);
ZimbraLog.gal.debug("remain: %d, limit: %d", remain, limit);
}
int count = 0;
boolean hasMore = false;
for (int itemId : changed.getFirst()) {
try {
MailItem item = mbox.getItemById(octxt, itemId, MailItem.Type.CONTACT);
if (item instanceof Contact) {
Contact c = (Contact) item;
if (filterAttr != null && !filterValue.equals(c.get(filterAttr))) {
continue;
}
callback.handleContact(c);
count++;
if (count % 100 == 0) {
ZimbraLog.gal.trace("processing #%s", count);
}
changeId = item.getModifiedSequence();
if (count == limit) {
hasMore = true;
break;
}
}
} catch (MailServiceException mse) {
if (MailServiceException.NO_SUCH_ITEM.equals(mse.getId())) {
ZimbraLog.gal.warn("skipping item %d due to no such item; probably deleted during sync", itemId, mse);
} else {
throw mse;
}
}
}
GalSyncToken newToken = new GalSyncToken(syncToken, mbox.getAccountId(), changeId);
ZimbraLog.gal.debug("computing new sync token for %s:%s", mbox.getAccountId(), newToken);
callback.setNewToken(newToken);
callback.setHasMoreResult(hasMore);
}
Aggregations