示例#1
0
 def _handleForm(self, mlist, category, subcat, cgidata, doc):
     # TK: If there is no hdrfilter_* in cgidata, we should not touch
     # the header filter rules.
     if not cgidata.has_key('hdrfilter_rebox_01'):
         return
     # First deal with
     rules = []
     # We start i at 1 and keep going until we no longer find items keyed
     # with the marked tags.
     i = 1
     downi = None
     while True:
         deltag    = 'hdrfilter_delete_%02d' % i
         reboxtag  = 'hdrfilter_rebox_%02d' % i
         actiontag = 'hdrfilter_action_%02d' % i
         wheretag  = 'hdrfilter_where_%02d' % i
         addtag    = 'hdrfilter_add_%02d' % i
         newtag    = 'hdrfilter_new_%02d' % i
         uptag     = 'hdrfilter_up_%02d' % i
         downtag   = 'hdrfilter_down_%02d' % i
         i += 1
         # Was this a delete?  If so, we can just ignore this entry
         if cgidata.has_key(deltag):
             continue
         # Get the data for the current box
         pattern = cgidata.getvalue(reboxtag)
         try:
             action  = int(cgidata.getvalue(actiontag))
             # We'll get a TypeError when the actiontag is missing and the
             # .getvalue() call returns None.
         except (ValueError, TypeError):
             action = mm_cfg.DEFER
         if pattern is None:
             # We came to the end of the boxes
             break
         if cgidata.has_key(newtag) and not pattern:
             # This new entry is incomplete.
             if i == 2:
                 # OK it is the first.
                 continue
             doc.addError(_("""Header filter rules require a pattern.
             Incomplete filter rules will be ignored."""))
             continue
         # Make sure the pattern was a legal regular expression.
         # Convert it to unicode if necessary.
         mo = re.match('.*charset=([-_a-z0-9]+)',
                       os.environ.get('CONTENT_TYPE', ''),
                       re.IGNORECASE
                      )
         if mo:
             cset = mo.group(1)
         else:
             cset = Utils.GetCharSet(mlist.preferred_language)
         try:
             upattern = Utils.xml_to_unicode(pattern, cset)
             re.compile(upattern)
             pattern = upattern
         except (re.error, TypeError):
             safepattern = Utils.websafe(pattern)
             doc.addError(_("""The header filter rule pattern
             '%(safepattern)s' is not a legal regular expression.  This
             rule will be ignored."""))
             continue
         # Was this an add item?
         if cgidata.has_key(addtag):
             # Where should the new one be added?
             where = cgidata.getvalue(wheretag)
             if where == 'before':
                 # Add a new empty rule box before the current one
                 rules.append(('', mm_cfg.DEFER, True))
                 rules.append((pattern, action, False))
                 # Default is to add it after...
             else:
                 rules.append((pattern, action, False))
                 rules.append(('', mm_cfg.DEFER, True))
         # Was this an up movement?
         elif cgidata.has_key(uptag):
             # As long as this one isn't the first rule, move it up
             if rules:
                 rules.insert(-1, (pattern, action, False))
             else:
                 rules.append((pattern, action, False))
         # Was this the down movement?
         elif cgidata.has_key(downtag):
             downi = i - 2
             rules.append((pattern, action, False))
         # Otherwise, just retain this one in the list
         else:
             rules.append((pattern, action, False))
     # Move any down button filter rule
     if downi is not None:
         rule = rules[downi]
         del rules[downi]
         rules.insert(downi+1, rule)
     mlist.header_filter_rules = rules
示例#2
0
 def _handleForm(self, mlist, category, subcat, cgidata, doc):
     # TK: If there is no hdrfilter_* in cgidata, we should not touch
     # the header filter rules.
     if not cgidata.has_key('hdrfilter_rebox_01'):
         return
     # First deal with
     rules = []
     # We start i at 1 and keep going until we no longer find items keyed
     # with the marked tags.
     i = 1
     downi = None
     while True:
         deltag = 'hdrfilter_delete_%02d' % i
         reboxtag = 'hdrfilter_rebox_%02d' % i
         actiontag = 'hdrfilter_action_%02d' % i
         wheretag = 'hdrfilter_where_%02d' % i
         addtag = 'hdrfilter_add_%02d' % i
         newtag = 'hdrfilter_new_%02d' % i
         uptag = 'hdrfilter_up_%02d' % i
         downtag = 'hdrfilter_down_%02d' % i
         i += 1
         # Was this a delete?  If so, we can just ignore this entry
         if cgidata.has_key(deltag):
             continue
         # Get the data for the current box
         pattern = cgidata.getfirst(reboxtag)
         try:
             action = int(cgidata.getfirst(actiontag))
             # We'll get a TypeError when the actiontag is missing and the
             # .getvalue() call returns None.
         except (ValueError, TypeError):
             action = mm_cfg.DEFER
         if pattern is None:
             # We came to the end of the boxes
             break
         if cgidata.has_key(newtag) and not pattern:
             # This new entry is incomplete.
             if i == 2:
                 # OK it is the first.
                 continue
             doc.addError(
                 _("""Header filter rules require a pattern.
             Incomplete filter rules will be ignored."""))
             continue
         # Make sure the pattern was a legal regular expression.
         # Convert it to unicode if necessary.
         mo = re.match('.*charset=([-_a-z0-9]+)',
                       os.environ.get('CONTENT_TYPE', ''), re.IGNORECASE)
         if mo:
             cset = mo.group(1)
         else:
             cset = Utils.GetCharSet(mlist.preferred_language)
         try:
             upattern = Utils.xml_to_unicode(pattern, cset)
             re.compile(upattern)
             pattern = upattern
         except (re.error, TypeError):
             safepattern = Utils.websafe(pattern)
             doc.addError(
                 _("""The header filter rule pattern
             '%(safepattern)s' is not a legal regular expression.  This
             rule will be ignored."""))
             continue
         # Was this an add item?
         if cgidata.has_key(addtag):
             # Where should the new one be added?
             where = cgidata.getfirst(wheretag)
             if where == 'before':
                 # Add a new empty rule box before the current one
                 rules.append(('', mm_cfg.DEFER, True))
                 rules.append((pattern, action, False))
                 # Default is to add it after...
             else:
                 rules.append((pattern, action, False))
                 rules.append(('', mm_cfg.DEFER, True))
         # Was this an up movement?
         elif cgidata.has_key(uptag):
             # As long as this one isn't the first rule, move it up
             if rules:
                 rules.insert(-1, (pattern, action, False))
             else:
                 rules.append((pattern, action, False))
         # Was this the down movement?
         elif cgidata.has_key(downtag):
             downi = i - 2
             rules.append((pattern, action, False))
         # Otherwise, just retain this one in the list
         else:
             rules.append((pattern, action, False))
     # Move any down button filter rule
     if downi is not None:
         rule = rules[downi]
         del rules[downi]
         rules.insert(downi + 1, rule)
     mlist.header_filter_rules = rules
示例#3
0
def process(mlist, msg, msgdata):
    # Before anything else, check DMARC if necessary.  We do this as early
    # as possible so reject/discard actions trump other holds/approvals and
    # wrap/munge actions get flagged even for approved messages.
    # But not for owner mail which should not be subject to DMARC reject or
    # discard actions.
    if not msgdata.get('toowner'):
        msgdata['from_is_list'] = 0
        dn, addr = parseaddr(msg.get('from'))
        if addr and mlist.dmarc_moderation_action > 0:
            if Utils.IsDMARCProhibited(mlist, addr):
                # Note that for dmarc_moderation_action, 0 = Accept,
                #    1 = Munge, 2 = Wrap, 3 = Reject, 4 = Discard
                if mlist.dmarc_moderation_action == 1:
                    msgdata['from_is_list'] = 1
                elif mlist.dmarc_moderation_action == 2:
                    msgdata['from_is_list'] = 2
                elif mlist.dmarc_moderation_action == 3:
                    # Reject
                    text = mlist.dmarc_moderation_notice
                    if text:
                        text = Utils.wrap(text)
                    else:
                        listowner = mlist.GetOwnerEmail()
                        text = Utils.wrap(
                            _("""You are not allowed to post to this mailing list From: a domain which
publishes a DMARC policy of reject or quarantine, and your message has been
automatically rejected.  If you think that your messages are being rejected in
error, contact the mailing list owner at %(listowner)s."""))
                    raise Errors.RejectMessage, text
                elif mlist.dmarc_moderation_action == 4:
                    raise Errors.DiscardMessage

        # Get member address if any.
        for sender in msg.get_senders():
            if mlist.isMember(sender):
                break
        else:
            sender = msg.get_sender()
        if (mlist.member_verbosity_threshold > 0
                and Utils.IsVerboseMember(mlist, sender)):
            mlist.setMemberOption(sender, mm_cfg.Moderate, 1)
            syslog('vette',
                   '%s: Automatically Moderated %s for verbose postings.',
                   mlist.real_name, sender)

    if msgdata.get('approved'):
        return
    # First do site hard coded header spam checks
    for header, regex in mm_cfg.KNOWN_SPAMMERS:
        cre = re.compile(regex, re.IGNORECASE)
        for value in msg.get_all(header, []):
            mo = cre.search(value)
            if mo:
                # we've detected spam, so throw the message away
                raise SpamDetected
    # Now do header_filter_rules
    # TK: Collect headers in sub-parts because attachment filename
    # extension may be a clue to possible virus/spam.
    headers = u''
    # Get the character set of the lists preferred language for headers
    lcset = Utils.GetCharSet(mlist.preferred_language)
    for p in msg.walk():
        headers += getDecodedHeaders(p, lcset)
    for patterns, action, empty in mlist.header_filter_rules:
        if action == mm_cfg.DEFER:
            continue
        for pattern in patterns.splitlines():
            if pattern.startswith('#'):
                continue
            # ignore 'empty' patterns
            if not pattern.strip():
                continue
            pattern = Utils.xml_to_unicode(pattern, lcset)
            pattern = normalize(mm_cfg.NORMALIZE_FORM, pattern)
            try:
                mo = re.search(pattern, headers,
                               re.IGNORECASE | re.MULTILINE | re.UNICODE)
            except (re.error, TypeError):
                syslog('error',
                       'ignoring header_filter_rules invalid pattern: %s',
                       pattern)
            if mo:
                if action == mm_cfg.DISCARD:
                    raise Errors.DiscardMessage
                if action == mm_cfg.REJECT:
                    if msgdata.get('toowner'):
                        # Don't send rejection notice if addressed to '-owner'
                        # because it may trigger a loop of notices if the
                        # sender address is forged.  We just discard it here.
                        raise Errors.DiscardMessage
                    raise Errors.RejectMessage(
                        _('Message rejected by filter rule match'))
                if action == mm_cfg.HOLD:
                    if msgdata.get('toowner'):
                        # Don't hold '-owner' addressed message.  We just
                        # pass it here but list-owner can set this to be
                        # discarded on the GUI if he wants.
                        return
                    hold_for_approval(mlist, msg, msgdata,
                                      HeaderMatchHold(pattern))
                if action == mm_cfg.ACCEPT:
                    return