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))
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))
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)
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)
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)
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)