#! /usr/bin/env python
# -*- coding: utf-8 -*-

# Pour envoyer effectivement des mails, il faut désactiver le debug
debug = 1

import os,sys

import smtplib

# Le smtp est assez capricieux
for i in range(5):
    try:
        mail = smtplib.SMTP('localhost')
    except:
        sleep(5)
        if i == 4:
            print "Impossible de se connecter au SMTP"
            sys.exit(1)
    

# On définit ici une liste d'adresse mail qui ne sont pas à prévenir
# à utiliser par exemple si on a commencé à prévenir des adhérents mais que
# tous ne l'ont pas été
try :
    exempts = []
    file = open('/home/salles/mails_envoyes',"r")
    line = file.readline()
    while line : 
        exempts.append(line.strip())
        line = file.readline()
    file.close()
except :
    print "Aucune exemption d'adresses mails ne sera prise en compte"

# On définit ici la liste des mails perdus et qui sont inscrits dans les logs
# Dans le cas du 11/09/2007, les mails perdus étaient identifiables avec
# le message "too many hops"
# On a donc créé le fichier mails_perdus avec la commande suivante :
# cat /var/log/mail.log | grep "too many hops" | grep '(!) FWD via SMTP' | awk -F ' ' '{print $1 " " $2 " " $3 " " $11 " " $12 " " $13}' | tr \[:upper:\] \[:lower:\] | sed 's/,$//g' > mails_perdus
# Le fichier se présente alors sous la forme :
# Mois Jour Heure <emetteur@adresse.mail> -> <recepteur@adresse.mail.2>
file = open('/home/salles/mails_perdus',"r")

# On crée les 2 dictionnaire qui vont contenir les 2 types d'avertissemnts à
# communiquer :
# - les messages envoyés par des adhérents au serveur mais qui ne sont pas 
#partis vers leur destinataire
unsend = {}
# - les messages reçus par le serveur mais non distribués aux adhérents
unreceived = {}

def is_crans(mail) :
    """ Détermine si l'adresse mail concerne un adhérent"""
    # Je remarque que les adresses de clubs et de mailings-listes ne sont
    # pas pris en compte @lists.crans.
    if mail.find('@crans.') > 0 :
        return 1
    else :
        return 0
    

def append(dict, chain, value, date) :
    """ Définit une méthode pour ajouter un mail perdu dans l'un des
dictionnaires.
Les dictionnaires ont pour clés l'adresse mail d'un adhérent aux quelles
sont associés une liste des mails perdus sur la forme ['adresse_mail2', 'date']
"""
    if not dict.has_key(chain) :
        # Si la clé n'existe pas : initialisation
        dict[chain] = [ [value, date] ]
    else :
        # Sinon on ajoute le nouveau mail perdu à la liste existante
        dict[chain].append([value, date])
    
# On traite maintenant la liste des mails perdus
line = file.readline()
# Pour chaque mail perdu
while line:
    datas = line.split()
    # Il pourrait y avoir plusieurs expéditeurs pour le même mail
    senders = datas[3].split(",")
    # Il peut y avoir plusieurs destinataires pour un mail (ça c'est sur)
    receivers = datas[5].split(",")
    # On tente d'enlever les adresses nulles de ces 2 listes
    try :
        senders.remove(u'<>')
    except :
        pass
    try :
        receivers.remove(u'<>')
    except :
        pass
    
    # On reformate le champ date en inversant Jour et Mois
    date = u"%s %s %s" % (datas[1], datas[0], datas[2])

    # Pour chaque couple de mail perdu associé à une source et un destinataire
    for sender in senders :
        for receiver in receivers :
            # L'expediteur et le receveur sont du crans ?
            if is_crans(sender) and is_crans(receiver) :
                append(unsend, sender, receiver, date)
                append(unreceived, receiver, sender, date)
            # L'expediteur est du crans ?
            if is_crans(sender) and not is_crans(receiver) :
                append(unsend, sender, receiver, date)
            # Le receveur est du crans ?
            if is_crans(receiver) and not is_crans(sender) :
                append(unreceived, receiver, sender, date)

    # On passe à la ligne suivante
    line = file.readline()

file.close()


# On traite le formatage des mails pour indiquer aux adhérents les
# mails qui ne leur ont pas été délivrés
for adh in unreceived.keys() :
    text = u"""From: CRANS (Nounous) <nounous@crans.org>
To: %s
Subject: [CRANS] Dysfonctionnement du serveur de mail
Content-Type: text/plain; charset="iso-8859-15"

Bonjour,

Nous t'informons que suite à une erreur sur le serveur de mail
de l'association, il est fort probable que nous ayons égaré des
messages te concernant dans la période allant du lundi 10/09/2007
23h00 à ce mardi 11/09/2007 9h50.

Tu trouveras ci-dessous le détail des messages que tu n'as pas pu
recevoir et/ou envoyer.\n""" % adh
    for unrecv in unreceived[adh] :
        text += u""" - mail non reçu : envoyé par %s avant le %s\n""" % (unrecv[0], unrecv[1])
    text += u"""Nous te conseillons de contacter les personnes qui figurent dans
cette liste si tu souhaites recevoir leur message, car elles n'ont
pas été informé de cette erreur de livraison.
"""
# Au passage, on vérifie s'il n'y a pas des mails que l'adhérents auraient
# voulu envoyer qui se seraient aussi perdus
    if unsend.has_key(adh) :
        text += u"""
"""
        for unsnd in unsend[adh] :
            text += u""" - mail non envoyé : adressé à %s le %s\n""" % (unsnd[0], unsnd[1])
            
        text += u"""Pour les mails que tu as pu essayé d'envoyer, et si ce n'est pas
déjà le cas, il te faut les réexpédier si tu souhaites que tes
destinataires les reçoivent.
"""

    text += u"""
-- 
Les nounous du CRANS"""
    text = text.encode('iso-8859-15')
    if debug :
        print text
    else :
        if adh not in exempts :
            # On essaie d'envoyer le mail car on peut rencontrer des spams
            # dans le lot des mails perdus
            try :
                mail.sendmail('nounous@crans.org', adh, text)
            except :
                pass

    
# Le message est légèrement différent dans le cas où l'adhérent n'a perdu
# des mails qu'à l'envoi.
for adh in unsend.keys() :
    if not unreceived.has_key(adh) :
        text = u"""From: CRANS (Nounous) <nounous@crans.org>
To: %s
Subject: [CRANS] Dysfonctionnement du serveur de mail
Content-Type: text/plain; charset="iso-8859-15"

Bonjour,

Nous t'informons que suite à une erreur sur le serveur de mail
de l'association, il est fort probable que nous n'ayons pas pu
transmettre certains de tes messages dans la période allant du
lundi 10/09/2007 23h00 à ce mardi 11/09/2007 9h50.

Tu trouveras ci-dessous le détail des messages que nous n'avons
pas pu envoyer.\n""" % adh

        for unsnd in unsend[adh] :
            text += u""" - mail non envoyé : adressé à %s le %s\n""" % (unsnd[0], unsnd[1])

        text += u"""Pour les mails que tu as pu essayé d'envoyer, et si ce n'est
pas déjà le cas, il te faut les réexpédier si tu souhaites que tes
destinataires les reçoivent.
"""

        text += u"""
-- 
Les nounous du CRANS"""
        text = text.encode('iso-8859-15')
        if debug :
            print text
        else:
            if adh not in exempts :
                try :
                    mail.sendmail('nounous@crans.org', adh, text)
                except :
                    pass

                
