From fe5f42fa5f4dba32b852e328afe11d18b534c4c2 Mon Sep 17 00:00:00 2001 From: Vincent Le Gallic Date: Sat, 5 Oct 2013 01:38:32 +0200 Subject: [PATCH] =?utf8?q?[mailman]=20M=C3=A9ta-script=20pour=20parser=20l?= =?utf8?q?es=20mails=20et=20batch-exterminer?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- mailman_bad_guys.py | 8 +++- mailman_search_and_destroy.py | 74 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100755 mailman_search_and_destroy.py diff --git a/mailman_bad_guys.py b/mailman_bad_guys.py index eba0821..3b817ee 100755 --- a/mailman_bad_guys.py +++ b/mailman_bad_guys.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding:utf-8 -*- +## TODO : Supprimer aussi les modérateurs/administrateurs """Pour trouver dans quelle(s) ML(s) est quelqu'un et l'en virer. À exécuter sur redisdead. @@ -54,8 +55,8 @@ def exterminate(mail, ml): l.Save() l.Unlock() -if __name__ == "__main__": - bad_guy = sys.argv[1].decode("utf-8").lower() +def exterminate_this_guy(bad_guy): + """Trouve les MLs auxquelles est abonné ``bad_guy`` et l'en supprime en demandant confirmation.""" mls = get_mls_from_mail(bad_guy) mls.sort() if mls: @@ -66,3 +67,6 @@ if __name__ == "__main__": exterminate(bad_guy, n) else: print("No mailing list found") + +if __name__ == "__main__": + bad_guy = sys.argv[1].decode("utf-8").lower() diff --git a/mailman_search_and_destroy.py b/mailman_search_and_destroy.py new file mode 100755 index 0000000..0c6b82b --- /dev/null +++ b/mailman_search_and_destroy.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +## TODO : Les alias (matcher Original-recipient ET Final-recipient ?) + +""" Pour récupérer les adresses mails des badguys à virer des MLs + (On considère que les mails son non lus) + On appelle ensuite mailman_bad_guys dessus """ + +import os +import re + +#import mailman_bad_guys + +#: Regexp permettant de vérifier que ce fichier est bien un mail d'erreur +delivery_pattern = ur'Content-Type: multipart/report; report-type=delivery-status;' +delivery_regex = re.compile(delivery_pattern) + +#: Regexp qui matche très exactement une adresse mail +#: (oui, bon, c'est pas très RFC-compliant) +justmail_pattern = ur"[^\s\n]+@[^\s\n]+" + +#: Regexp permettant de trouver la ligne contenant le mail invalide et un peu de contexte +find_context_pattern = ur"(?PFinal-Recipient: rfc822; ?(?P%s)(?:.*\n){5})" % (justmail_pattern,) +find_context_regex = re.compile(find_context_pattern) + +#: Dossier contenant les mails d'erreur de mailman +mailman_problems_dir = os.path.expanduser(u"~/Mail/.Cr@ns.Problems.4-Human-made.Mailman/cur/") + +def list_files(where=mailman_problems_dir): + """Récupère la liste des noms de fichiers contenant a priori des échecs mailman.""" + files = [mailman_problems_dir + f for f in os.listdir(mailman_problems_dir) if f.endswith(":2,a")] + return files + +def get_context_and_mail(text): + """Récupère l'adresse mail qui a causé un échec et quelques lignes de contexte.""" + results = [m.groupdict() for m in find_context_regex.finditer(text)] + return results + +def files_to_mails(files): + """Trouve tous les mails des bad guys.""" + bad_guys = [] + for mailfile in files: + mail = open(mailfile).read().decode("utf-8") + # On regarde si il s'agit bien d'un échec + isdelivery = len(delivery_regex.findall(mail)) > 0 + if isdelivery: + results = get_context_and_mail(mail) + if results: + [result] = results + bad_guys.append(result) + else: + ans = raw_input("Headers not found. Show mail ? ") + if not ans in "nN": + print mail + return bad_guys + +def serial_exterminate(bad_guys): + """Extermine tout le monde, en demandant confirmation.""" + import mailman_bad_guys + infos = mailman_bad_guys.get_all() + for bad_guy in bad_guys: + print bad_guy["context"] + mailman_bad_guys.exterminate_this_guy(bad_guy["mail"], infos) + print "\n\n\n" + +def do_all(): + """Fait le boulot.""" + files = list_files() + bad_guys = files_to_mails(files) + serial_exterminate(bad_guys) + +if __name__ == "__main__": + do_all() -- 2.39.2