Search in sources :

Example 1 with Node

use of org.apache.jsieve.parser.generated.Node in project zm-mailbox by Zimbra.

the class RuleManager method applyRulesToOutgoingMessage.

public static List<ItemId> applyRulesToOutgoingMessage(OperationContext octxt, Mailbox mailbox, ParsedMessage pm, int sentFolderId, boolean noICal, int flags, String[] tags, int convId) throws ServiceException {
    List<ItemId> addedMessageIds = null;
    OutgoingMessageHandler handler = new OutgoingMessageHandler(mailbox, pm, sentFolderId, noICal, flags, tags, convId, octxt);
    ZimbraMailAdapter mailAdapter = new ZimbraMailAdapter(mailbox, handler);
    try {
        Account account = mailbox.getAccount();
        Node node = getRulesNode(account, FilterType.OUTGOING, true);
        if (node != null) {
            SIEVE_FACTORY.evaluate(mailAdapter, node);
            // multiple fileinto may result in multiple copies of the messages in different folders
            addedMessageIds = mailAdapter.getAddedMessageIds();
        }
    } catch (Exception e) {
        ZimbraLog.filter.warn("An error occurred while processing filter rules. Filing message to %s.", handler.getDefaultFolderPath(), e);
    } catch (TokenMgrError e) {
        ZimbraLog.filter.warn("An error occurred while processing filter rules. Filing message to %s.", handler.getDefaultFolderPath(), e);
    }
    if (addedMessageIds == null) {
        // Filter rules were not processed.  File to the default folder.
        Message msg = mailAdapter.keep(KeepType.IMPLICIT_KEEP);
        addedMessageIds = new ArrayList<ItemId>(1);
        addedMessageIds.add(new ItemId(msg));
    }
    return addedMessageIds;
}
Also used : Account(com.zimbra.cs.account.Account) Message(com.zimbra.cs.mailbox.Message) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) Node(org.apache.jsieve.parser.generated.Node) TokenMgrError(org.apache.jsieve.parser.generated.TokenMgrError) ItemId(com.zimbra.cs.service.util.ItemId) ServiceException(com.zimbra.common.service.ServiceException) ParseException(org.apache.jsieve.parser.generated.ParseException) SieveException(org.apache.jsieve.exception.SieveException) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) IOException(java.io.IOException) UnsupportedEncodingException(java.io.UnsupportedEncodingException)

Example 2 with Node

use of org.apache.jsieve.parser.generated.Node 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);
    }
}
Also used : Account(com.zimbra.cs.account.Account) Server(com.zimbra.cs.account.Server) HashMap(java.util.HashMap) Cos(com.zimbra.cs.account.Cos) Node(org.apache.jsieve.parser.generated.Node) TokenMgrError(org.apache.jsieve.parser.generated.TokenMgrError) SieveException(org.apache.jsieve.exception.SieveException) ParseException(org.apache.jsieve.parser.generated.ParseException) Domain(com.zimbra.cs.account.Domain)

Example 3 with Node

use of org.apache.jsieve.parser.generated.Node in project zm-mailbox by Zimbra.

the class RuleManager method getRulesNode.

/**
     * Returns the parsed filter rules for the given account.  If no cached
     * copy of the parsed rules exists, parses the script returned by
     * {@link #getRules(com.zimbra.cs.account.Account, String)} and caches the result on the <tt>Account</tt>.
     *
     * @param account the owner account of the filter rule
     * @param filterType <tt>FilterType.INCOMING</tt> or <tt>FilterType.OUTGOING</tt>
     * @param useAdminRule TRUE to return a combined sieve rule of admin sieve(s) and user defined rule.  FALSE to return only a user defined rule.
     *
     * @see Account#setCachedData(String, Object)
     * @throws ParseException if there was an error while parsing the Sieve script
     */
private static Node getRulesNode(Account account, FilterType filterType, boolean useAdminRule) throws ParseException {
    String rulesCacheKey = null;
    // user-defined sieve rule
    String sieveScriptAttrName = null;
    // admin-defined sieve rule applied before and after user sieve
    String adminRuleBeforeAttrName = null;
    String adminRuleAfterAttrName = null;
    if (filterType == FilterType.INCOMING) {
        if (useAdminRule) {
            rulesCacheKey = ADMIN_FILTER_RULES_CACHE_KEY;
        } else {
            rulesCacheKey = FILTER_RULES_CACHE_KEY;
        }
        sieveScriptAttrName = Provisioning.A_zimbraMailSieveScript;
        adminRuleBeforeAttrName = Provisioning.A_zimbraAdminSieveScriptBefore;
        adminRuleAfterAttrName = Provisioning.A_zimbraAdminSieveScriptAfter;
    } else {
        if (useAdminRule) {
            rulesCacheKey = ADMIN_OUTGOING_FILTER_RULES_CACHE_KEY;
        } else {
            rulesCacheKey = OUTGOING_FILTER_RULES_CACHE_KEY;
        }
        sieveScriptAttrName = Provisioning.A_zimbraMailOutgoingSieveScript;
        adminRuleBeforeAttrName = Provisioning.A_zimbraAdminOutgoingSieveScriptBefore;
        adminRuleAfterAttrName = Provisioning.A_zimbraAdminOutgoingSieveScriptAfter;
    }
    Node node = (Node) account.getCachedData(rulesCacheKey);
    if (node == null) {
        String script = getRules(account, sieveScriptAttrName);
        String debugScript = script;
        if (useAdminRule) {
            /*
                 * Sandwitches the user-defined sieve rule
                 * between the admin-defined rules.
                 */
            StringBuilder requiresPart = new StringBuilder();
            String adminRuleBefore = getRules(account, adminRuleBeforeAttrName);
            String adminRuleAfter = getRules(account, adminRuleAfterAttrName);
            String debugAdminRuleBefore = adminRuleBefore;
            String debugAdminRuleAfter = adminRuleAfter;
            if (adminRuleBefore == null) {
                debugAdminRuleBefore = "";
                adminRuleBefore = "";
            } else {
                List<String> splits = splitScript(adminRuleBefore);
                requiresPart.append(splits.get(0));
                debugAdminRuleBefore = adminRuleBefore = splits.get(1);
            }
            if (script == null) {
                debugScript = "";
                script = "";
            } else {
                List<String> splits = splitScript(script);
                requiresPart.append(splits.get(0));
                script = "\nzimbravariablesctrl :reset;\n" + splits.get(1);
                debugScript = splits.get(1);
            }
            if (adminRuleAfter == null) {
                debugAdminRuleAfter = "";
                adminRuleAfter = "";
            } else {
                List<String> splits = splitScript(adminRuleAfter);
                requiresPart.append(splits.get(0));
                adminRuleAfter = "\nzimbravariablesctrl :reset;\n" + splits.get(1);
                debugAdminRuleAfter = splits.get(1);
            }
            /*
                 * Since "require" is only allowed before other commands,
                 * the "require" part at the beginning of each sieve rule
                 * text will be cut, and pasted into the very top of the
                 * combined rule. RFC-wise, it is okay to declare the
                 * "require" commands multiple times.
                 */
            script = requiresPart.toString() + adminRuleBefore + script + adminRuleAfter;
            debugScript = requiresPart.toString() + "\n# AdminBefore script\n" + debugAdminRuleBefore + "\n# End user script\n" + debugScript + "\n# AdminAfter script\n" + debugAdminRuleAfter;
        }
        if (script == null) {
            script = "";
        }
        ZimbraLog.filter.debug("filterType[%s] useAdminRule[%s] rule[%s]", filterType == FilterType.INCOMING ? "incoming" : "outgoing", useAdminRule ? "true" : "false", debugScript);
        node = parse(script);
        account.setCachedData(rulesCacheKey, node);
    }
    return node;
}
Also used : Node(org.apache.jsieve.parser.generated.Node)

Example 4 with Node

use of org.apache.jsieve.parser.generated.Node in project zm-mailbox by Zimbra.

the class RuleManager method applyRulesToIncomingMessage.

/**
     * Adds a message to a mailbox.  If filter rules exist, processes
     * the filter rules.  Otherwise, files to <tt>Inbox</tt> or <tt>Spam</tt>.
     *
     * @param allowFilterToMountpoint if <tt>false</tt>, rules
     * @return the list of message id's that were added, or an empty list.
     */
public static List<ItemId> applyRulesToIncomingMessage(OperationContext octxt, Mailbox mailbox, ParsedMessage pm, int size, String recipient, LmtpEnvelope env, DeliveryContext sharedDeliveryCtxt, int incomingFolderId, boolean noICal, boolean allowFilterToMountpoint) throws ServiceException {
    List<ItemId> addedMessageIds = null;
    IncomingMessageHandler handler = new IncomingMessageHandler(octxt, sharedDeliveryCtxt, mailbox, recipient, pm, size, incomingFolderId, noICal);
    ZimbraMailAdapter mailAdapter = new ZimbraMailAdapter(mailbox, handler);
    mailAdapter.setEnvelope(env);
    mailAdapter.setAllowFilterToMountpoint(allowFilterToMountpoint);
    try {
        Account account = mailbox.getAccount();
        Node node = getRulesNode(account, FilterType.INCOMING, true);
        // Determine whether to apply rules
        boolean applyRules = true;
        if (node == null) {
            applyRules = false;
        }
        if (SpamHandler.isSpam(handler.getMimeMessage()) && !account.getBooleanAttr(Provisioning.A_zimbraSpamApplyUserFilters, false)) {
            // Don't apply user filters to spam by default
            applyRules = false;
        }
        if (applyRules) {
            SIEVE_FACTORY.evaluate(mailAdapter, node);
            // multiple fileinto may result in multiple copies of the messages in different folders
            addedMessageIds = mailAdapter.getAddedMessageIds();
        }
    } catch (ErejectException ex) {
        throw DeliveryServiceException.DELIVERY_REJECTED(ex.getMessage(), ex);
    } catch (Exception e) {
        ZimbraLog.filter.warn("An error occurred while processing filter rules. Filing message to %s.", handler.getDefaultFolderPath(), e);
    } catch (TokenMgrError e) {
        // Workaround for bug 19576.  Certain parse errors can cause JavaCC to throw an Error
        // instead of an Exception.  Woo.
        ZimbraLog.filter.warn("An error occurred while processing filter rules. Filing message to %s.", handler.getDefaultFolderPath(), e);
    }
    if (addedMessageIds == null) {
        // Filter rules were not processed.  File to the default folder.
        Message msg = mailAdapter.keep(KeepType.IMPLICIT_KEEP);
        addedMessageIds = new ArrayList<ItemId>(1);
        addedMessageIds.add(new ItemId(msg));
    }
    return addedMessageIds;
}
Also used : Account(com.zimbra.cs.account.Account) Message(com.zimbra.cs.mailbox.Message) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) Node(org.apache.jsieve.parser.generated.Node) TokenMgrError(org.apache.jsieve.parser.generated.TokenMgrError) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) ItemId(com.zimbra.cs.service.util.ItemId) ServiceException(com.zimbra.common.service.ServiceException) ParseException(org.apache.jsieve.parser.generated.ParseException) SieveException(org.apache.jsieve.exception.SieveException) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) IOException(java.io.IOException) UnsupportedEncodingException(java.io.UnsupportedEncodingException)

Example 5 with Node

use of org.apache.jsieve.parser.generated.Node in project zm-mailbox by Zimbra.

the class RuleRewriter method action.

private void action(Element elem, Node node) {
    int numChildren = node.jjtGetNumChildren();
    for (int i = 0; i < numChildren; i++) {
        Node childNode = node.jjtGetChild(i);
        if (childNode instanceof ASTstring) {
            String val = ((SieveNode) childNode).getValue().toString();
            if (val.startsWith("text:")) {
                elem.addText(val.substring(5));
            } else {
                // Put quotes around value to maintain backward compatibility
                // with ZCS 5.x.  See bug 39911.
                StringBuilder buf = new StringBuilder();
                if (!val.startsWith("\"")) {
                    buf.append('"');
                }
                buf.append(val);
                if (!val.endsWith("\"")) {
                    buf.append('"');
                }
                elem.addElement(MailConstants.E_FILTER_ARG).setText(buf.toString());
            }
        } else {
            action(elem, childNode);
        }
    }
}
Also used : ASTstring(org.apache.jsieve.parser.generated.ASTstring) Node(org.apache.jsieve.parser.generated.Node) SieveNode(org.apache.jsieve.parser.SieveNode) Mountpoint(com.zimbra.cs.mailbox.Mountpoint)

Aggregations

Node (org.apache.jsieve.parser.generated.Node)22 ParseException (org.apache.jsieve.parser.generated.ParseException)10 SieveNode (org.apache.jsieve.parser.SieveNode)9 TokenMgrError (org.apache.jsieve.parser.generated.TokenMgrError)6 Mountpoint (com.zimbra.cs.mailbox.Mountpoint)5 ArrayList (java.util.ArrayList)5 Account (com.zimbra.cs.account.Account)4 ServiceException (com.zimbra.common.service.ServiceException)3 Element (com.zimbra.common.soap.Element)3 UnsupportedEncodingException (java.io.UnsupportedEncodingException)3 SieveException (org.apache.jsieve.exception.SieveException)3 ASTcommand (org.apache.jsieve.parser.generated.ASTcommand)3 DeliveryServiceException (com.zimbra.common.service.DeliveryServiceException)2 ErejectException (com.zimbra.cs.filter.jsieve.ErejectException)2 Message (com.zimbra.cs.mailbox.Message)2 ParsedMessage (com.zimbra.cs.mime.ParsedMessage)2 ItemId (com.zimbra.cs.service.util.ItemId)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 IOException (java.io.IOException)2 List (java.util.List)2