use of com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException in project zm-mailbox by Zimbra.
the class ExportAndDeleteItems method handle.
@Override
public Element handle(Element requst, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
checkRight(zsc, context, null, AdminRight.PR_SYSTEM_ADMIN_ONLY);
// Parse request.
ExportAndDeleteItemsRequest req = JaxbUtil.elementToJaxb(requst);
ExportAndDeleteMailboxSpec mailbox = req.getMailbox();
if (mailbox == null) {
throw ServiceException.INVALID_REQUEST("empty mbox id", null);
}
Mailbox mbox = MailboxManager.getInstance().getMailboxById(mailbox.getId());
Multimap<Integer, Integer> idRevs = HashMultimap.create();
for (ExportAndDeleteItemSpec item : mailbox.getItems()) {
idRevs.put(item.getId(), item.getVersion());
}
String dirPath = req.getExportDir();
String prefix = req.getExportFilenamePrefix();
// Lock the mailbox, to make sure that another thread doesn't modify the items we're exporting/deleting.
mbox.lock.lock();
try {
DbConnection conn = null;
try {
conn = DbPool.getConnection();
if (dirPath != null) {
File exportDir = new File(dirPath);
if (!exportDir.isDirectory()) {
DbPool.quietClose(conn);
throw ServiceException.INVALID_REQUEST(dirPath + " is not a directory", null);
}
String filePath = makePath(dirPath, DbMailItem.TABLE_MAIL_ITEM, prefix);
export(conn, mbox, DbMailItem.TABLE_MAIL_ITEM, "id", idRevs, filePath);
filePath = makePath(dirPath, DbMailItem.TABLE_MAIL_ITEM_DUMPSTER, prefix);
export(conn, mbox, DbMailItem.TABLE_MAIL_ITEM_DUMPSTER, "id", idRevs, filePath);
filePath = makePath(dirPath, DbMailItem.TABLE_REVISION, prefix);
export(conn, mbox, DbMailItem.TABLE_REVISION, "item_id", idRevs, filePath);
filePath = makePath(dirPath, DbMailItem.TABLE_REVISION_DUMPSTER, prefix);
export(conn, mbox, DbMailItem.TABLE_REVISION_DUMPSTER, "item_id", idRevs, filePath);
filePath = makePath(dirPath, DbMailItem.TABLE_APPOINTMENT, prefix);
export(conn, mbox, DbMailItem.TABLE_APPOINTMENT, "item_id", idRevs, filePath);
filePath = makePath(dirPath, DbMailItem.TABLE_APPOINTMENT_DUMPSTER, prefix);
export(conn, mbox, DbMailItem.TABLE_APPOINTMENT_DUMPSTER, "item_id", idRevs, filePath);
}
// delete item from mail_item and revision table
for (Integer itemId : idRevs.keySet()) {
Collection<Integer> revs = idRevs.get(itemId);
for (int rev : revs) {
if (rev == 0) {
// delete all revisions to make sure we delete all blobs
List<MailItem> list = null;
try {
list = mbox.getAllRevisions(null, itemId, MailItem.Type.UNKNOWN);
} catch (NoSuchItemException ex) {
// exception happens when we try to delete a mail_item which is already in mail_item_dumpster
continue;
}
for (MailItem item : list) {
if (item.getType() == MailItem.Type.DOCUMENT) {
mbox.purgeRevision(null, itemId, item.getVersion(), false);
}
}
mbox.delete(null, itemId, MailItem.Type.UNKNOWN, null);
break;
} else if (!revs.contains(0)) {
try {
mbox.purgeRevision(null, itemId, rev, false);
} catch (NoSuchItemException ex) {
// exception happens when we try to delete a revision which is already in revision_dumpster
continue;
}
}
}
}
// Delete items from mail_item_dumpster & revision_dumpster tables just
// incase moved to dumpster tables
DbBlobConsistency.delete(conn, mbox, idRevs);
} finally {
conn.commit();
DbPool.quietClose(conn);
}
} finally {
mbox.lock.release();
}
return zsc.createElement(AdminConstants.EXPORT_AND_DELETE_ITEMS_RESPONSE);
}
use of com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException in project zm-mailbox by Zimbra.
the class Mailbox method reanalyze.
/** Recalculates the size, metadata, etc. for an existing MailItem and
* persists that information to the database. Maintains any existing
* mutable metadata. Updates mailbox and folder sizes appropriately.
*
* @param id The item ID of the MailItem to reanalyze.
* @param type The item's type (e.g. {@link MailItem#TYPE_MESSAGE}).
* @param data The (optional) extra item data for indexing (e.g.
* a Message's {@link ParsedMessage}. */
void reanalyze(int id, MailItem.Type type, Object data, long size) throws ServiceException {
boolean success = false;
try {
beginTransaction("reanalyze", null);
MailItem item;
try {
item = getItemById(id, type, false);
} catch (NoSuchItemException e) {
// fallback to dumpster
item = getItemById(id, type, true);
}
item.reanalyze(data, size);
success = true;
} finally {
endTransaction(success);
}
}
use of com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException in project zm-mailbox by Zimbra.
the class ApplyFilterRules method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Account account = getRequestedAccount(zsc);
if (!canAccessAccount(zsc, account))
throw ServiceException.PERM_DENIED("cannot access account");
// Get rules.
String fullScript = getRules(account);
if (StringUtil.isNullOrEmpty(fullScript)) {
throw ServiceException.INVALID_REQUEST("Account has no filter rules defined.", null);
}
List<Element> ruleElements = request.getElement(MailConstants.E_FILTER_RULES).listElements(MailConstants.E_FILTER_RULE);
if (ruleElements.size() == 0) {
String msg = String.format("No %s elements specified.", MailConstants.E_FILTER_RULE);
throw ServiceException.INVALID_REQUEST(msg, null);
}
// Concatenate script parts and create a new script to run on existing messages.
StringBuilder buf = new StringBuilder();
for (Element ruleEl : ruleElements) {
String name = ruleEl.getAttribute(MailConstants.A_NAME);
String singleRule = RuleManager.getRuleByName(fullScript, name);
if (singleRule == null) {
String msg = String.format("Could not find a rule named '%s'", name);
throw ServiceException.INVALID_REQUEST(msg, null);
}
buf.append(singleRule).append("\n");
}
String partialScript = buf.toString();
ZimbraLog.filter.debug("Applying partial script to existing messages: %s", partialScript);
Node node = null;
try {
node = RuleManager.parse(partialScript);
} catch (ParseException e) {
throw ServiceException.FAILURE("Unable to parse Sieve script: " + partialScript, e);
}
// Get the ids of the messages to filter.
Element msgEl = request.getOptionalElement(MailConstants.E_MSG);
String query = getElementText(request, MailConstants.E_QUERY);
if (msgEl != null && query != null) {
String msg = String.format("Cannot specify both %s and %s elements.", MailConstants.E_MSG, MailConstants.E_QUERY);
throw ServiceException.INVALID_REQUEST(msg, null);
}
Mailbox mbox = getRequestedMailbox(zsc);
List<Integer> messageIds = new ArrayList<Integer>();
List<Integer> affectedIds = new ArrayList<Integer>();
OperationContext octxt = getOperationContext(zsc, context);
if (msgEl != null) {
String[] ids = msgEl.getAttribute(MailConstants.A_IDS).split(",");
for (String id : ids) {
messageIds.add(Integer.valueOf(id));
}
} else if (query != null) {
ZimbraQueryResults results = null;
try {
results = mbox.index.search(octxt, query, EnumSet.of(MailItem.Type.MESSAGE), SortBy.NONE, Integer.MAX_VALUE);
while (results.hasNext()) {
ZimbraHit hit = results.getNext();
messageIds.add(hit.getItemId());
}
} catch (Exception e) {
String msg = String.format("Unable to run search for query: '%s'", query);
throw ServiceException.INVALID_REQUEST(msg, e);
} finally {
Closeables.closeQuietly(results);
}
} else {
String msg = String.format("Must specify either the %s or %s element.", MailConstants.E_MSG, MailConstants.E_QUERY);
throw ServiceException.INVALID_REQUEST(msg, null);
}
int max = account.getFilterBatchSize();
if (messageIds.size() > max) {
throw ServiceException.INVALID_REQUEST("Attempted to apply filter rules to " + messageIds.size() + " messages, which exceeded the limit of " + max, null);
}
ZimbraLog.filter.info("Applying filter rules to %s existing messages.", messageIds.size());
long sleepInterval = account.getFilterSleepInterval();
// Apply filter rules.
for (int i = 0; i < messageIds.size(); i++) {
if (i > 0 && sleepInterval > 0) {
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
}
}
int id = messageIds.get(i);
try {
mbox.getMessageById(octxt, id);
if (RuleManager.applyRulesToExistingMessage(octxt, mbox, id, node)) {
affectedIds.add(id);
}
} catch (NoSuchItemException e) {
// Message was deleted since the search was done (bug 41609).
ZimbraLog.filter.info("Skipping message %d: %s.", id, e.toString());
} catch (ServiceException e) {
ZimbraLog.filter.warn("Unable to filter message %d.", id, e);
}
}
// Send response.
Element response = zsc.createElement(getResponseElementName());
if (affectedIds.size() > 0) {
response.addElement(MailConstants.E_MSG).addAttribute(MailConstants.A_IDS, StringUtil.join(",", affectedIds));
}
return response;
}
use of com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException in project zm-mailbox by Zimbra.
the class IncomingMessageHandler method fileInto.
@Override
public ItemId fileInto(String folderPath, Collection<ActionFlag> flagActions, String[] tags) throws ServiceException {
ItemId id = FilterUtil.addMessage(dctxt, mailbox, parsedMessage, recipientAddress, folderPath, false, FilterUtil.getFlagBitmask(flagActions, Flag.BITMASK_UNREAD), tags, Mailbox.ID_AUTO_INCREMENT, octxt);
// the spam folder (bug 37164).
try {
Folder folder = mailbox.getFolderByPath(octxt, folderPath);
if (folder.getId() == Mailbox.ID_FOLDER_SPAM && id.isLocal()) {
SpamReport report = new SpamReport(true, "filter", folderPath);
SpamHandler.getInstance().handle(octxt, mailbox, id.getId(), MailItem.Type.MESSAGE, report);
}
} catch (NoSuchItemException e) {
ZimbraLog.filter.debug("Unable to do spam training for message %s because folder path %s does not exist.", id, folderPath);
} catch (ServiceException e) {
ZimbraLog.filter.warn("Unable to do spam training for message %s.", id, e);
}
return id;
}
use of com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException in project zm-mailbox by Zimbra.
the class Mailbox method delete.
/**
* Delete the <tt>MailItem</tt>s with the given ids. If there is no <tt>MailItem</tt> for a given id, that id is
* ignored. If the id maps to an existing <tt>MailItem</tt> of an incompatible type, however, an error is thrown.
*
* @param octxt operation context or {@code null}
* @param itemIds item ids
* @param type item type or {@link MailItem.Type#UNKNOWN}
* @param tcon target constraint or {@code null}
* @param useEmptyForFolders empty folder {@code true} or {@code false}
* @param nonExistingItems object of {@link ArrayList} or {@code null}
*/
private void delete(OperationContext octxt, int[] itemIds, MailItem.Type type, TargetConstraint tcon, boolean useEmptyForFolders, List<Integer> nonExistingItems) throws ServiceException {
DeleteItem redoRecorder = new DeleteItem(mId, itemIds, type, tcon);
List<Integer> folderIds = Lists.newArrayList();
boolean success = false;
try {
beginTransaction("delete", octxt, redoRecorder);
setOperationTargetConstraint(tcon);
for (int id : itemIds) {
if (id == ID_AUTO_INCREMENT) {
continue;
}
MailItem item;
try {
item = getItemById(id, MailItem.Type.UNKNOWN);
} catch (NoSuchItemException nsie) {
if (nonExistingItems != null) {
nonExistingItems.add(id);
}
// trying to delete nonexistent things is A-OK!
continue;
}
// however, trying to delete messages and passing in a folder ID is not OK
if (!MailItem.isAcceptableType(type, item.getType())) {
throw MailItem.noSuchItem(id, type);
} else if (!checkItemChangeID(item) && item instanceof Tag) {
throw MailServiceException.MODIFY_CONFLICT();
}
if (useEmptyForFolders && MailItem.Type.FOLDER.equals(item.getType())) {
// removed later to allow batching delete of contents in there own transactions
folderIds.add(id);
} else {
// delete the item, but don't write the tombstone until we're finished...
item.delete(false);
}
}
// deletes have already been collected, so fetch the tombstones and write once
TypedIdList tombstones = collectPendingTombstones();
if (tombstones != null && !tombstones.isEmpty()) {
DbMailItem.writeTombstones(this, tombstones);
}
success = true;
} finally {
endTransaction(success);
}
for (Integer folderId : folderIds) {
emptyFolder(octxt, folderId, true, /* removeTopLevelFolder */
true, /* removeSubfolders */
tcon);
}
}
Aggregations