use of org.apache.jsieve.parser.generated.ParseException in project zm-mailbox by Zimbra.
the class RuleManager method setRules.
/**
* Saves the filter rules.
*
* @param entry the account/domain/cos/server for which the rules are to be saved
* @param script the sieve script, or <code>null</code> or empty string if
* all rules should be deleted
* @param sieveScriptAttrName
* @param rulesCacheKey
* @throws ServiceException
*/
private static void setRules(Entry entry, String script, String sieveScriptAttrName, String rulesCacheKey) throws ServiceException {
if (entry instanceof Account) {
ZimbraLog.filter.debug("Setting filter rules for account %s:\n%s", ((Account) entry).getName(), script);
} else if (entry instanceof Domain) {
ZimbraLog.filter.debug("Setting filter rules for domian %s:\n%s", ((Domain) entry).getName(), script);
} else if (entry instanceof Cos) {
ZimbraLog.filter.debug("Setting filter rules for cos %s:\n%s", ((Cos) entry).getName(), script);
} else if (entry instanceof Server) {
ZimbraLog.filter.debug("Setting filter rules for server %s:\n%s", ((Server) entry).getName(), script);
}
if (script == null) {
script = "";
}
try {
Node node = parse(script);
// evaluate against dummy mail adapter to catch more errors
SIEVE_FACTORY.evaluate(new DummyMailAdapter(), node);
// save
Map<String, Object> attrs = new HashMap<String, Object>();
attrs.put(sieveScriptAttrName, script);
Provisioning.getInstance().modifyAttrs(entry, attrs);
entry.setCachedData(rulesCacheKey, node);
} catch (ParseException e) {
ZimbraLog.filter.error("Unable to parse script:\n" + script);
throw ServiceException.PARSE_ERROR("parsing Sieve script", e);
} catch (TokenMgrError e) {
ZimbraLog.filter.error("Unable to parse script:\n" + script);
throw ServiceException.PARSE_ERROR("parsing Sieve script", e);
} catch (SieveException e) {
ZimbraLog.filter.error("Unable to evaluate script:\n" + script);
throw ServiceException.PARSE_ERROR("evaluating Sieve script", e);
}
}
use of org.apache.jsieve.parser.generated.ParseException 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 org.apache.jsieve.parser.generated.ParseException in project zm-mailbox by Zimbra.
the class RuleManager method parse.
/**
* Parses the sieve script and returns the root to the resulting node tree.
*/
public static Node parse(String script) throws ParseException {
ByteArrayInputStream sin;
try {
sin = new ByteArrayInputStream(script.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new ParseException(e.getMessage());
}
Node node = null;
try {
node = SIEVE_FACTORY.parse(sin);
} catch (TokenMgrError e) {
// filter string without any undefined escape sequences.
try {
sin = new ByteArrayInputStream(ignoreBackslash(script).getBytes("UTF-8"));
} catch (UnsupportedEncodingException uee) {
throw new ParseException(uee.getMessage());
}
node = SIEVE_FACTORY.parse(sin);
}
return node;
}
use of org.apache.jsieve.parser.generated.ParseException in project zm-mailbox by Zimbra.
the class RuleManager method getRulesAsXML.
private static List<FilterRule> getRulesAsXML(Account account, FilterType filterType) throws ServiceException {
Node node;
try {
node = getRulesNode(account, filterType, false);
} catch (ParseException e) {
throw ServiceException.PARSE_ERROR("parsing Sieve script", e);
} catch (TokenMgrError e) {
throw ServiceException.PARSE_ERROR("parsing Sieve script", e);
}
String sieveScriptAttrName = null;
if (filterType == FilterType.INCOMING) {
sieveScriptAttrName = Provisioning.A_zimbraMailSieveScript;
} else {
sieveScriptAttrName = Provisioning.A_zimbraMailOutgoingSieveScript;
}
SieveToSoap sieveToSoap = new SieveToSoap(getRuleNames(account.getAttr(sieveScriptAttrName)));
sieveToSoap.accept(node);
return sieveToSoap.toFilterRules();
}
use of org.apache.jsieve.parser.generated.ParseException in project zm-mailbox by Zimbra.
the class RuleManager method tagDeleted.
private static void tagDeleted(Account account, String tagName, String sieveScriptAttrName, String rulesCacheKey) throws ServiceException {
String script = getRules(account, sieveScriptAttrName);
if (script != null) {
Node node;
try {
node = parse(script);
} catch (ParseException e) {
ZimbraLog.filter.warn("Unable to update %s after tag '%s' was deleted.", sieveScriptAttrName, tagName, e);
return;
}
TagDeleted deleted = new TagDeleted(tagName);
deleted.accept(node);
if (deleted.modified()) {
// Kind of a hacky way to convert a Node tree to a script. We
// convert to XML first, and then to a String. Unfortunately
// jSieve 0.2 doesn't have an API that generates a script from
// a Node tree.
List<String> ruleNames = getRuleNames(script);
SieveToSoap sieveToSoap = new SieveToSoap(ruleNames);
sieveToSoap.accept(node);
SoapToSieve soapToSieve = new SoapToSieve(sieveToSoap.toFilterRules());
String newScript = soapToSieve.getSieveScript();
setRules(account, newScript, sieveScriptAttrName, rulesCacheKey);
ZimbraLog.filter.info("Updated %s after tag %s was deleted.", sieveScriptAttrName, tagName);
ZimbraLog.filter.debug("Old rules:\n%s, new rules:\n%s", script, newScript);
}
}
}
Aggregations