示例#1
0
def process(mlist, msg, msgdata):
	pfLists = ("profox", "profoxtech")
	listname = mlist.real_name
	tm = time.strftime("%Y.%m.%d %H:%M:%S",time.localtime())
	
	if listname.lower() in ("profox", "profoxtech"):
		if "X-Suspect-Mail: yes" in msg:
			# already flagged
			return
		snd = msg.get_sender()
		if snd == "*****@*****.**":
			# It'll get discarded anyway
			return
		
		logMsgs = []
		logMsgs.append("%s-> List: %s, Sender: %s" % (tm, listname, msg.get_sender()))
		cmd = "/usr/local/mailman/bin/find_member %s" % snd
		proc = Popen([cmd], shell=True, stdin=PIPE, stdout=PIPE, close_fds=True)
		f, stdin = (proc.stdout, proc.stdin)
		res = f.read().replace(" ", "").splitlines()
		res = res[1:]
		logMsgs.append("Findmember LISTS: %s" % str(res))
		ok = (pfLists[0] in res) or (pfLists[1] in res)
		logMsgs.append("\tOK LIST: %s" % ok)
		if not ok:
			ok = snd in mlist.accept_these_nonmembers
			logMsgs.append("\tOK ACCEPT: %s" % ok)
		if not ok:
			# Check the other list
			otherNameList = ["profox", "profoxtech"]
			otherNameList.remove(mlist.internal_name())
			otherName = otherNameList[0]
			otherList = MailList(otherName)
			ok = snd in otherList.accept_these_nonmembers
			logMsgs.append("\tOK OTHER ACCEPT: %s" % ok)
			otherList.Unlock()
		if not ok:
			logMsgs.append("\tNot a subscriber: %s" % snd)
			syslog("vette", "%s post from %s held: non-subscriber to either ProFox list. " % (listname, snd))
			#syslog("vette", str(res))
			try:
				Hold.hold_for_approval(mlist, msg, msgdata, ProFoxNonSubHold(snd))
			except StandardError, e:
				logMsgs.append("ERROR: %s" % str(e))
				
		if not ok:
			open("/usr/local/mailman/profox.log", "a").write("\n".join(logMsgs))
示例#2
0
def process(mlist, msg, msgdata):
    if msgdata.get('approved'):
        return
    
    score, symbols = check_message(mlist, str(msg))

    if MEMBER_BONUS != 0:
        for sender in msg.get_senders():
            if mlist.isMember(sender) or \
                   mlist.GetPattern(sender, mlist.accept_these_nonmembers, at_list='accept_these_nonmembers'):
                score -= MEMBER_BONUS
                break

    if score > DISCARD_SCORE:
        listname = mlist.real_name
        sender = msg.get_sender()
        syslog('vette', '%s post from %s discarded: '
                        'SpamAssassin score was %g (discard threshold is %g)'
                          % (listname, sender, score, DISCARD_SCORE))
        raise SpamAssassinDiscard
    elif score > HOLD_SCORE:
        Hold.hold_for_approval(mlist, msg, msgdata,
                               SpamAssassinHold(score, symbols))
示例#3
0
def process(mlist, msg, msgdata):
    if msgdata.get('approved') or msgdata.get('fromusenet'):
        return
    # First of all, is the poster a member or not?
    for sender in msg.get_senders():
        if mlist.isMember(sender):
            break
    else:
        sender = None
    if sender:
        # If the member's moderation flag is on, then perform the moderation
        # action.
        if mlist.getMemberOption(sender, mm_cfg.Moderate):
            # Note that for member_moderation_action, 0==Hold, 1=Reject,
            # 2==Discard
            if mlist.member_moderation_action == 0:
                # Hold.  BAW: WIBNI we could add the member_moderation_notice
                # to the notice sent back to the sender?
                msgdata['sender'] = sender
                Hold.hold_for_approval(mlist, msg, msgdata,
                                       ModeratedMemberPost)
            elif mlist.member_moderation_action == 1:
                # Reject
                text = mlist.member_moderation_notice
                if text:
                    text = Utils.wrap(text)
                else:
                    # Use the default RejectMessage notice string
                    text = None
                raise Errors.RejectMessage, text
            elif mlist.member_moderation_action == 2:
                # Discard.  BAW: Again, it would be nice if we could send a
                # discard notice to the sender
                raise Errors.DiscardMessage
            else:
                assert 0, 'bad member_moderation_action'
        # Should we do anything explict to mark this message as getting past
        # this point?  No, because further pipeline handlers will need to do
        # their own thing.
        return
    else:
        sender = msg.get_sender()
    # From here on out, we're dealing with non-members.
    listname = mlist.internal_name()
    if matches_p(sender, mlist.accept_these_nonmembers, listname):
        return
    if matches_p(sender, mlist.hold_these_nonmembers, listname):
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
        # No return
    if matches_p(sender, mlist.reject_these_nonmembers, listname):
        do_reject(mlist)
        # No return
    if matches_p(sender, mlist.discard_these_nonmembers, listname):
        do_discard(mlist, msg)
        # No return
    # Okay, so the sender wasn't specified explicitly by any of the non-member
    # moderation configuration variables.  Handle by way of generic non-member
    # action.
    assert 0 <= mlist.generic_nonmember_action <= 4
    if mlist.generic_nonmember_action == 0:
        # Accept
        return
    elif mlist.generic_nonmember_action == 1:
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
    elif mlist.generic_nonmember_action == 2:
        do_reject(mlist)
    elif mlist.generic_nonmember_action == 3:
        do_discard(mlist, msg)
示例#4
0
def process(mlist, msg, msgdata):
    if msgdata.get('approved') or msgdata.get('fromusenet'):
        return
    # First of all, is the poster a member or not?
    for sender in msg.get_senders():
        if mlist.isMember(sender):
            break
    else:
        sender = None
    if sender:
        # If the member's moderation flag is on, then perform the moderation
        # action.
        if mlist.getMemberOption(sender, mm_cfg.Moderate):
            # Note that for member_moderation_action, 0==Hold, 1=Reject,
            # 2==Discard
            if mlist.member_moderation_action == 0:
                # Hold.  BAW: WIBNI we could add the member_moderation_notice
                # to the notice sent back to the sender?
                msgdata['sender'] = sender
                Hold.hold_for_approval(mlist, msg, msgdata,
                                       ModeratedMemberPost)
            elif mlist.member_moderation_action == 1:
                # Reject
                text = mlist.member_moderation_notice
                if text:
                    text = Utils.wrap(text)
                else:
                    # Use the default RejectMessage notice string
                    text = None
                raise Errors.RejectMessage, text
            elif mlist.member_moderation_action == 2:
                # Discard.  BAW: Again, it would be nice if we could send a
                # discard notice to the sender
                raise Errors.DiscardMessage
            else:
                assert 0, 'bad member_moderation_action'
        # Should we do anything explict to mark this message as getting past
        # this point?  No, because further pipeline handlers will need to do
        # their own thing.
        return
    else:
        sender = msg.get_sender()
    # From here on out, we're dealing with non-members.
    listname = mlist.internal_name()
    if matches_p(sender, mlist.accept_these_nonmembers, listname):
        return
    if matches_p(sender, mlist.hold_these_nonmembers, listname):
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
        # No return
    if matches_p(sender, mlist.reject_these_nonmembers, listname):
        do_reject(mlist)
        # No return
    if matches_p(sender, mlist.discard_these_nonmembers, listname):
        do_discard(mlist, msg)
        # No return
    # Okay, so the sender wasn't specified explicitly by any of the non-member
    # moderation configuration variables.  Handle by way of generic non-member
    # action.
    assert 0 <= mlist.generic_nonmember_action <= 4
    if mlist.generic_nonmember_action == 0:
        # Accept
        return
    elif mlist.generic_nonmember_action == 1:
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
    elif mlist.generic_nonmember_action == 2:
        do_reject(mlist)
    elif mlist.generic_nonmember_action == 3:
        do_discard(mlist, msg)
示例#5
0
def process(mlist, msg, msgdata):
    if msgdata.get('approved'):
        return
    # Deal with encrypted messages

    encrypted_gpg = False
    encrypted_smime = False
    signed = False
    key_ids = []
    signedByMember = False
    # To record with which properties we received this message.
    # This will be important later when distributing it: we want
    # to be able to support policies like "was incoming signed?
    # then distribute signed."
    msgdata['encrypted_gpg'] = False
    msgdata['encrypted_smime'] = False
    msgdata['signed_gpg'] = False
    msgdata['signed_smime'] = False

    # legal values are:
    #    0 = "No"
    #    1 = "Voluntary"
    #    2 = "Mandatory"
    if mlist.encrypt_policy!=0:
        # if msg is encrypted, we should decrypt. Try both supported types.
        (encrypted_gpg, signed, key_ids) = decryptGpg(mlist, msg, msgdata)
        (encrypted_smime, signedByMember) = decryptSmime(mlist, msg, msgdata)
        if encrypted_gpg:
            msgdata['encrypted_gpg'] = True
        if encrypted_smime:
            msgdata['encrypted_smime'] = True

        if mlist.encrypt_policy==2 and not encrypted_gpg and not encrypted_smime:
            syslog('gpg','Throwing RejectMessage exception: Message has to be GPG encrypted')
            raise Errors.RejectMessage, "Message has to be encrypted!"

    if mlist.sign_policy!=0 and not signed:
        # PGP signature matters, we have not checked while decrypting
        gh = GPGUtils.GPGHelper(mlist)
        payload = ''
        payloadmsg = None
        signatures = []
        if msg.get_content_type()=='multipart/signed' and msg.get_param('protocol')=='application/pgp-signature' and msg.is_multipart():
            # handle detached signatures, these look like:
            #
            # Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="x0ZPnva+gsdVsg/k"
            # Content-Disposition: inline
            #
            #
            # --x0ZPnva+gsdVsg/k
            # Content-Type: text/plain; charset=us-ascii
            # Content-Disposition: inline
            #
            # hello
            #
            # --x0ZPnva+gsdVsg/k
            # Content-Type: application/pgp-signature; name="signature.asc"
            # Content-Description: Digital signature
            # Content-Disposition: inline
            #
            # -----BEGIN PGP SIGNATURE-----
            # Version: GnuPG v1.2.5 (GNU/Linux)
            #
            # iD8DBQFCQDTGPSnqOAwU/4wRAsoZAKDtN6Pn1dXjC/DAQhqOLHNI6VfNigCfaDPs
            # FRJlhlGvyhkpx4soGR+CLxE=
            # =AmS5
            # -----END PGP SIGNATURE-----
            #
            # --x0ZPnva+gsdVsg/k--
            #
            # for verification, use payload INCLUDING MIME header:
            #
            # 'Content-Type: text/plain; charset=us-ascii
            #  Content-Disposition: inline
            #
            #  hello
            # '
            # Thanks Wessel Dankers for hint.

            for submsg in msg.get_payload():
                if submsg.get_content_type()=='application/pgp-signature':
                    signatures.append(submsg.get_payload())
                else:
                    if not payload:
                        # yes, including headers
                        payload = submsg.as_string()
                    else:
                        # we only deal with exactly one payload part and one or more signatures parts
                        syslog('gpg','multipart/signed message with more than one body')
                        do_discard(mlist, msg)
        elif msg.get_content_type()=='text/plain' and not msg.is_multipart():
             # handle inline signature; message looks like e.g.
             #
             # Content-Type: text/plain; charset=iso-8859-1
             # Content-Disposition: inline
             # Content-Transfer-Encoding: 8bit
             # MIME-Version: 1.0
             #
             # -----BEGIN PGP SIGNED MESSAGE-----
             # Hash: SHA1
             #
             # blah blah
             #
             # -----BEGIN PGP SIGNATURE-----
             # Version: GnuPG v1.4.0 (GNU/Linux)
             #
             # iD8DBQFCPtWXW5ql+IAeqTIRAirPAK....
             # -----END PGP SIGNATURE-----
             signatures = [None]
             payload = msg.get_payload(decode=True)
             payloadmsg = msg
        elif msg.get_content_type()=='multipart/alternative' and msg.is_multipart():
            #GPG signed plaintext with HTML version
            for submsg in msg.get_payload():
                if submsg.get_content_type()=='text/plain':
                    if not payload:
                        # text without headers
                        signatures = [None]
                        payload = submsg.get_payload(decode=True)
                        payloadmsg = submsg
                    else:
                        # we only deal with exactly one payload part
                        Utils.report_submission(msg['Message-ID'],'Confused by MIME message structure, discarding.')
                        syslog('gpg','multipart/alternative message with more than one plaintext')                        
                        do_discard(mlist, msg)
        elif msg.get_content_type()=='multipart/mixed' and msg.is_multipart():
            #GPG signed plaintext with attachments. Use first plaintext part (more text attachments are perfectly valid here)
            #TODO submsg may be multipart/alternative itself or whatever structure - is that used in the wild anywhere?
            for submsg in msg.get_payload():
                if submsg.get_content_type()=='text/plain':
                    # text without headers
                    payload = submsg.get_payload(decode=True)
                    payloadmsg = submsg
                    if payload.lstrip().startswith('-----BEGIN PGP '):
                        signatures = [None]
                        break
                elif submsg.get_content_type() in set(['application/pgp-encrypted', 'application/pgp']):
                    signatures = [None]
                    payload = submsg.get_payload(decode=True)
                    payloadmsg = submsg
                    submsg.set_type('text/plain; charset="utf-8"')
                    break
                elif submsg.get_content_type()=='multipart/alternative' and submsg.is_multipart():
                    #GPG signed plaintext with HTML version
                    for subsubmsg in submsg.get_payload():
                        if subsubmsg.get_content_type()=='text/plain':
                            if not payload:
                                # text without headers
                                payload = subsubmsg.get_payload(decode=True)
                                if payload.lstrip().startswith('-----BEGIN PGP '):
                                    signatures = [None]
                                    payloadmsg = subsubmsg
                            else:
                                # we only deal with exactly one payload part
                                syslog('gpg','multipart/alternative message with more than one plaintext')
                                Utils.report_submission(msg['Message-ID'],'Confused by MIME message structure, discarding.')
                                do_discard(mlist, msg)
                    if len(signatures) == 0:
                        payload = None
                        payloadmsg = None
                    elif payload:
                        break

        #TODO S/MIME broken atm
        #for signature in signatures:
        if signatures:
             syslog('gpg', "gonna verify payload with signature '%s'", signatures[0])
             key_ids.extend(gh.verifyMessage(payload, signatures[0],
                                             decrypted_checksum=mm_cfg.SCRUBBER_ADD_PAYLOAD_HASH_FILENAME))
        else:
            Utils.report_submission(msg['Message-ID'],'No clearsigned text part found, discarding.')


    if mlist.sign_policy!=0 and not signedByMember:
        # S/MIME signature matters, we have not checked while decrypting
        sm = SMIMEUtils.SMIMEHelper(mlist)
        payload = ''
        signature = ''

        syslog('gpg', "gonna verify SMIME message")
        signedByMember = sm.verifyMessage(msg)
        # raise Errors.NotYetImplemented, "SMIMEUtils doesn't yet do verifyMessage"

    # By now we know whether we have any valid signatures on the message.
    if signedByMember:
        msgdata['signed_smime'] = True
    if key_ids:
        msgdata['signed_gpg'] = True
        if payloadmsg and mm_cfg.SCRUBBER_ADD_PAYLOAD_HASH_FILENAME:
            sha = key_ids.pop(0)
            msgfrom = key_ids[0]
            #Kill the message if such text+signature was already posted.
            #Payload(spaces, newlines) is normalized by gpg decryption before hashing.
            if ospath.exists(ospath.join(mlist.archive_dir(),'attachments','links', msgfrom + '_' + sha)):
                Utils.report_submission(msg['Message-ID'],'Detected attempt to resubmit duplicate clearsigned text, discarding.')
                syslog('gpg','Attempt to pass clearsigned duplicate fp: %s sha1: %s' % (msgfrom, sha))
                do_discard(mlist, msg)

            payloadmsg.add_header(mm_cfg.SCRUBBER_SHA1SUM_HEADER, sha)
            payloadmsg.add_header(mm_cfg.SCRUBBER_SIGNEDBY_HEADER, msgfrom)


    if mlist.sign_policy!=0:
        if not key_ids and not signedByMember and mlist.sign_policy==2:
            Utils.report_submission(msg['Message-ID'],'Signature verification on clearsigned text failed, discarding. Review the message in your sent mail folder for wordwrap or similar mutilations of clearsigned text.')
            syslog('gpg','No valid signatures on message')
            do_discard(mlist, msg)

        if key_ids:
            gh = GPGUtils.GPGHelper(mlist)
            senderMatchesKey = False
            for key_id in key_ids:
                key_addrs = gh.getMailaddrs(key_id)
                for sender in msg.get_senders():
                    for key_addr in key_addrs:
                        if sender==key_addr:
                            senderMatchesKey = True
                            break
            if not senderMatchesKey:
                syslog('gpg','Message signed by key %s which does not match message sender %s, passing anyway' %(key_ids,msg.get_senders()))
                #temp fix
                #do_discard(mlist, msg)
        #we use gpg keyring in lieu of memberlist
        signedByMember = True
#         for user in mlist.getMembers():
#             syslog('gpg','Checking signature: listmember %s',user)
#             for key_id in key_ids:
#                 syslog('gpg','Checking signature: key_id %s',key_id)
#                 try:
#                     ks=mlist.getGPGKeyIDs(user)
#                 except:
#                     ks=None
#                 if ks:
#                     for k in mlist.getGPGKeyIDs(user):
#                         syslog('gpg','Checking signature: keyid of listmember is %s',k)
#                         if k==key_id:
#                             signedByMember = True
#                             break

    # done dealing with most of gpg stuff

    # Is the poster a member or not?
    for sender in msg.get_senders():
        if mlist.isMember(sender):
            break
        for sender in Utils.check_eq_domains(sender,
                          mlist.equivalent_domains):
            if mlist.isMember(sender):
                break
        if mlist.isMember(sender):
            break
    else:
        sender = None
    if sender:
        # If posts need to be PGP signed, process signature.
        if mlist.sign_policy==2:
            if signedByMember==True:
                syslog('gpg','Message properly signed: distribute')
                return
            else:
                do_discard(mlist, msg)

        # If the member's moderation flag is on, then perform the moderation
        # action.
        if mlist.getMemberOption(sender, mm_cfg.Moderate):
            # Note that for member_moderation_action, 0==Hold, 1=Reject,
            # 2==Discard
            if mlist.member_moderation_action == 0:
                # Hold.  BAW: WIBNI we could add the member_moderation_notice
                # to the notice sent back to the sender?
                msgdata['sender'] = sender
                Hold.hold_for_approval(mlist, msg, msgdata,
                                       ModeratedMemberPost)
            elif mlist.member_moderation_action == 1:
                # Reject
                text = mlist.member_moderation_notice
                if text:
                    text = Utils.wrap(text)
                else:
                    # Use the default RejectMessage notice string
                    text = None
                raise Errors.RejectMessage, text
            elif mlist.member_moderation_action == 2:
                # Discard.  BAW: Again, it would be nice if we could send a
                # discard notice to the sender
                raise Errors.DiscardMessage
            else:
                assert 0, 'bad member_moderation_action'
        # Should we do anything explict to mark this message as getting past
        # this point?  No, because further pipeline handlers will need to do
        # their own thing.
        return
    else:
        sender = msg.get_sender()
    # From here on out, we're dealing with non-members.
    listname = mlist.internal_name()
    if matches_p(sender, mlist.accept_these_nonmembers, listname):
        return
    if matches_p(sender, mlist.hold_these_nonmembers, listname):
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
        # No return
    if matches_p(sender, mlist.reject_these_nonmembers, listname):
        do_reject(mlist)
        # No return
    if matches_p(sender, mlist.discard_these_nonmembers, listname):
        do_discard(mlist, msg)
        # No return
    # Okay, so the sender wasn't specified explicitly by any of the non-member
    # moderation configuration variables.  Handle by way of generic non-member
    # action.
    assert 0 <= mlist.generic_nonmember_action <= 4
    if mlist.generic_nonmember_action == 0 or msgdata.get('fromusenet'):
        # Accept
        return
    elif mlist.generic_nonmember_action == 1:
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
    elif mlist.generic_nonmember_action == 2:
        do_reject(mlist)
    elif mlist.generic_nonmember_action == 3:
        do_discard(mlist, msg)
示例#6
0
def process(mlist, msg, msgdata):
    if msgdata.get('approved'):
        return
    # Before anything else, check DMARC if necessary.
    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:
                    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
    # Then, is the poster a member or not?
    for sender in msg.get_senders():
        if mlist.isMember(sender):
            break
    else:
        sender = None
    if sender:
        # If the member's moderation flag is on, then perform the moderation
        # action.
        if mlist.getMemberOption(sender, mm_cfg.Moderate):
            # Note that for member_moderation_action, 0==Hold, 1=Reject,
            # 2==Discard
            if mlist.member_moderation_action == 0:
                # Hold.  BAW: WIBNI we could add the member_moderation_notice
                # to the notice sent back to the sender?
                msgdata['sender'] = sender
                Hold.hold_for_approval(mlist, msg, msgdata,
                                       ModeratedMemberPost)
            elif mlist.member_moderation_action == 1:
                # Reject
                text = mlist.member_moderation_notice
                if text:
                    text = Utils.wrap(text)
                else:
                    # Use the default RejectMessage notice string
                    text = None
                raise Errors.RejectMessage, text
            elif mlist.member_moderation_action == 2:
                # Discard.  BAW: Again, it would be nice if we could send a
                # discard notice to the sender
                raise Errors.DiscardMessage
            else:
                assert 0, 'bad member_moderation_action'
        # Should we do anything explict to mark this message as getting past
        # this point?  No, because further pipeline handlers will need to do
        # their own thing.
        return
    else:
        sender = msg.get_sender()
    # From here on out, we're dealing with non-members.
    listname = mlist.internal_name()
    if matches_p(sender, mlist.accept_these_nonmembers, listname):
        return
    if matches_p(sender, mlist.hold_these_nonmembers, listname):
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
        # No return
    if matches_p(sender, mlist.reject_these_nonmembers, listname):
        do_reject(mlist)
        # No return
    if matches_p(sender, mlist.discard_these_nonmembers, listname):
        do_discard(mlist, msg)
        # No return
    # Okay, so the sender wasn't specified explicitly by any of the non-member
    # moderation configuration variables.  Handle by way of generic non-member
    # action.
    assert 0 <= mlist.generic_nonmember_action <= 4
    if mlist.generic_nonmember_action == 0 or msgdata.get('fromusenet'):
        # Accept
        return
    elif mlist.generic_nonmember_action == 1:
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
    elif mlist.generic_nonmember_action == 2:
        do_reject(mlist)
    elif mlist.generic_nonmember_action == 3:
        do_discard(mlist, msg)
示例#7
0
def process(mlist, msg, msgdata):
    if msgdata.get('approved') or msgdata.get('fromusenet'):
        return

    # Deal with encrypted messages

    encrypted_gpg = False
    encrypted_smime = False
    signed = False
    key_ids = []
    signedByMember = False
    # To record with which properties we received this message.
    # This will be important later when distributing it: we want
    # to be able to support policies like "was incoming signed?
    # then distribute signed."
    msgdata['encrypted_gpg'] = False
    msgdata['encrypted_smime'] = False
    msgdata['signed_gpg'] = False
    msgdata['signed_smime'] = False

    # legal values are:
    #    0 = "No"
    #    1 = "Voluntary"
    #    2 = "Mandatory"
    if mlist.encrypt_policy!=0:
        # if msg is encrypted, we should decrypt. Try both supported types.
        (encrypted_gpg, signed, key_ids) = decryptGpg(mlist, msg, msgdata)
        (encrypted_smime, signedByMember) = decryptSmime(mlist, msg, msgdata)
        if encrypted_gpg:
            msgdata['encrypted_gpg'] = True
        if encrypted_smime:
            msgdata['encrypted_smime'] = True

    if mlist.encrypt_policy==2 and not encrypted_gpg and not encrypted_smime:
        syslog('gpg','Throwing RejectMessage exception: Message has to be GPG encryptedModerate')
        raise Errors.RejectMessage, "Message has to be encrypted!"

    if mlist.sign_policy!=0 and not signed:
        # PGP signature matters, we have not checked while decrypting
        gh = GPGUtils.GPGHelper(mlist)
        payload = ''
        signatures = []
        if msg.get_content_type()=='multipart/signed' and msg.get_param('protocol')=='application/pgp-signature' and msg.is_multipart():
            # handle detached signatures, these look like:
            #
            # Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="x0ZPnva+gsdVsg/k"
            # Content-Disposition: inline
            #
            #
            # --x0ZPnva+gsdVsg/k
            # Content-Type: text/plain; charset=us-ascii
            # Content-Disposition: inline
            #
            # hello
            #
            # --x0ZPnva+gsdVsg/k
            # Content-Type: application/pgp-signature; name="signature.asc"
            # Content-Description: Digital signature
            # Content-Disposition: inline
            #
            # -----BEGIN PGP SIGNATURE-----
            # Version: GnuPG v1.2.5 (GNU/Linux)
            #
            # iD8DBQFCQDTGPSnqOAwU/4wRAsoZAKDtN6Pn1dXjC/DAQhqOLHNI6VfNigCfaDPs
            # FRJlhlGvyhkpx4soGR+CLxE=
            # =AmS5
            # -----END PGP SIGNATURE-----
            #
            # --x0ZPnva+gsdVsg/k--
            #
            # for verification, use payload INCLUDING MIME header:
            #
            # 'Content-Type: text/plain; charset=us-ascii
            #  Content-Disposition: inline
            #
            #  hello
            # '
            # Thanks Wessel Dankers for hint.

            for submsg in msg.get_payload():
                if submsg.get_content_type()=='application/pgp-signature':
                    signatures.append(submsg.get_payload())
                else:
                    if not payload:
                        # yes, including headers
                        payload = submsg.as_string()
                    else:
                        # we only deal with exactly one payload part and one or more signatures parts
                        syslog('gpg','multipart/signed message with more than one body')
                        do_discard(mlist, msg)
        elif msg.get_content_type()=='text/plain' and not msg.is_multipart():
             # handle inline signature; message looks like e.g.
             #
             # Content-Type: text/plain; charset=iso-8859-1
             # Content-Disposition: inline
             # Content-Transfer-Encoding: 8bit
             # MIME-Version: 1.0
             #
             # -----BEGIN PGP SIGNED MESSAGE-----
             # Hash: SHA1
             #
             # blah blah
             #
             # -----BEGIN PGP SIGNATURE-----
             # Version: GnuPG v1.4.0 (GNU/Linux)
             #
             # iD8DBQFCPtWXW5ql+IAeqTIRAirPAK....
             # -----END PGP SIGNATURE-----
             signatures = [None]
             payload = msg.get_payload()

        for signature in signatures:
             syslog('gpg', "gonna verify payload with signature '%s'", signature)
             key_ids.extend(gh.verifyMessage(payload, signature))


    if mlist.sign_policy!=0 and not signedByMember:
        # S/MIME signature matters, we have not checked while decrypting
        sm = SMIMEUtils.SMIMEHelper(mlist)
        payload = ''
        signature = ''

        syslog('gpg', "gonna verify SMIME message")
        signedByMember = sm.verifyMessage(msg)
        # raise Errors.NotYetImplemented, "SMIMEUtils doesn't yet do verifyMessage"

    # By now we know whether we have any valid signatures on the message.
    if signedByMember:
        msgdata['signed_smime'] = True
    if key_ids:
        msgdata['signed_gpg'] = True

    if mlist.sign_policy!=0:
        if not key_ids and not signedByMember and mlist.sign_policy==2:
            syslog('gpg','No valid signatures on message')
            do_discard(mlist, msg)

        if key_ids:
            gh = GPGUtils.GPGHelper(mlist)
            senderMatchesKey = False
            for key_id in key_ids:
                key_addrs = gh.getMailaddrs(key_id)
                for sender in msg.get_senders():
                    for key_addr in key_addrs:
                        if sender==key_addr:
                            senderMatchesKey = True
                            break
            if not senderMatchesKey:
                syslog('gpg','Message signed by key which does not match message sender address')
                do_discard(mlist, msg)

        for user in mlist.getMembers():
            syslog('gpg','Checking signature: listmember %s',user)
            for key_id in key_ids:
                syslog('gpg','Checking signature: key_id %s',key_id)
                try:
                    ks=mlist.getGPGKeyIDs(user)
                except:
                    ks=None
                if ks:
                    for k in mlist.getGPGKeyIDs(user):
                        syslog('gpg','Checking signature: keyid of listmember is %s',k)
                        if k==key_id:
                            signedByMember = True
                            break

    # done dealing with most of gpg stuff

    # Is the poster a member or not?
    for sender in msg.get_senders():
        if mlist.isMember(sender):
            break
    else:
        sender = None
    if sender:
        # If posts need to be PGP signed, process signature.
        if mlist.sign_policy==2:
            if signedByMember==True:
                syslog('gpg','Message properly signed: distribute')
                return
            else:
                do_discard(mlist, msg)

        # If the member's moderation flag is on, then perform the moderation
        # action.
        if mlist.getMemberOption(sender, mm_cfg.Moderate):
            # Note that for member_moderation_action, 0==Hold, 1=Reject,
            # 2==Discard
            if mlist.member_moderation_action == 0:
                # Hold.  BAW: WIBNI we could add the member_moderation_notice
                # to the notice sent back to the sender?
                msgdata['sender'] = sender
                Hold.hold_for_approval(mlist, msg, msgdata,
                                       ModeratedMemberPost)
            elif mlist.member_moderation_action == 1:
                # Reject
                text = mlist.member_moderation_notice
                if text:
                    text = Utils.wrap(text)
                else:
                    # Use the default RejectMessage notice string
                    text = None
                raise Errors.RejectMessage, text
            elif mlist.member_moderation_action == 2:
                # Discard.  BAW: Again, it would be nice if we could send a
                # discard notice to the sender
                raise Errors.DiscardMessage
            else:
                assert 0, 'bad member_moderation_action'
        # Should we do anything explict to mark this message as getting past
        # this point?  No, because further pipeline handlers will need to do
        # their own thing.
        return
    else:
        sender = msg.get_sender()
    # From here on out, we're dealing with non-members.
    listname = mlist.internal_name()
    if matches_p(sender, mlist.accept_these_nonmembers, listname):
        return
    if matches_p(sender, mlist.hold_these_nonmembers, listname):
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
        # No return
    if matches_p(sender, mlist.reject_these_nonmembers, listname):
        do_reject(mlist)
        # No return
    if matches_p(sender, mlist.discard_these_nonmembers, listname):
        do_discard(mlist, msg)
        # No return
    # Okay, so the sender wasn't specified explicitly by any of the non-member
    # moderation configuration variables.  Handle by way of generic non-member
    # action.
    assert 0 <= mlist.generic_nonmember_action <= 4
    if mlist.generic_nonmember_action == 0:
        # Accept
        return
    elif mlist.generic_nonmember_action == 1:
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
    elif mlist.generic_nonmember_action == 2:
        do_reject(mlist)
    elif mlist.generic_nonmember_action == 3:
        do_discard(mlist, msg)