/*
    Fichier filtredest.c
    Auteur Bernard Chardonneau

    Logiciel libre, droits d'utilisation précisés en français
    dans le fichier : licence-fr.txt

    Traductions des droits d'utilisation dans les fichiers :
    licence-de.txt , licence-en.txt , licence-es.txt ,
    licence-it.txt , licence-nl.txt , licence-pt.txt ,
    licence-eo.txt , licence-eo-utf.txt

    Droits d'utilisation également sur la page web :
    http://libremail.tuxfamily.org/voir.php?page=droits


    Ce programme détruit les mails du serveur envoyés à des
    destinataires particuliers.
    Il sert à filtrer les spams envoyés à une adresse Email
    alphabétiquement voisines de l'adresse de celui qui reçoit
    le mail.

    La liste des adresses de destinataires interdites est mémorisée
    dans un fichier

    Un fichier de configuration est utilisé pour se connecter à la
    boite aux lettres.
*/


#define appli   // pour la déclaration de variables globales à l'application

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "messages.h"
#include "buflect.h"
#include "ficonf.h"
#include "pop.h"
#include "testchamp.h"
#include "trtentete.h"
#include "datecour.h"
#include "szchemin.h"


/* prototypes */
int testdest (int numes);


/* variables globales au source
   (pour éviter des tonnes de passages de paramètres) */


char **listedest;      // mémorise les destinataires interdits
int  sz_listedest;     // nombre de destinataires mémorisés dans listedest
char bufTo [120];      // buffer contenant le destinataire du mail
int  opto, optO;       // options de traitement

// chaine de caractère mémorisée pour éviter appels répétitifs à message ()
char mess_analys [50]; // message signalant l'analyse d'un mail



/* programme principal */

int main (int nbarg, char *varg[])
{
    // fichier contenant la liste des chaines à tester
    char fichliste [szchemin + 11];
    char *car_fichliste; // pointeur sur un caractère de ce fichier
    FILE *fconf;         // descripteur du fichier de configuration
    FILE *ftrace;        // fichier contenant les destinataires des mail refusés
    int  numes, nbmes;   // muméro du mail courant et nombre de mails
    char bufw [120];     // buffer d'envoi d'une requête de destruction de mail
    char datecour [10];  // date courante (pour le fichier des mails refusés)
    int  conserves = 0;  // nombre de mails conservés
    int  supprimes = 0;  // nombre de mails supprimés


    // récupération du nom de l'exécutable
    memcom (*varg);

    // se positionner sur le premier argument de filtredest
    nbarg --;
    varg ++;

    // initialisations valeur des options
    ftrace = NULL;
    opto = 0;
    optO = 0;

    // si le programme a été lancé avec des options
    while (nbarg >= 2 && **varg == '-')
    {
        // traitement des options
        switch (varg [0][1])
        {
            // option trace des mails supprimés
            case 't' : // ouvrir le fichier trace en écriture fin de fichier
                       ftrace = fopen (varg [1], "a");

                       // si nom de fichier correct
                       if (ftrace)
                           // initialiser la date courante
                           initdatecour (datecour);
                       else
                           // sinon, avertir l'utilisateur
                           // "Impossible d'écrire dans le fichier %s"
                           aff_err_arg ("IMPOS_ECR_FICH", varg [1]);

                       // sauter les arguments traités
                       nbarg -= 2;
                       varg  += 2;
                       break;

            // option test de la ligne d'entête d'origine (avant conversion)
            case 'o' : if (! optO)
                           opto = 1;
                       else
                           // "L'option -O est prioritaire sur l'option -o"
                           affiche_err ("PRIO_OPT_O");

                       // sauter l'argument traité
                       nbarg --;
                       varg  ++;
                       break;

            // option test de la ligne d'entête d'origine (avant conversion)
            case 'O' : optO = 1;

                       if (opto)
                           // "L'option -O est prioritaire sur l'option -o"
                           affiche_err ("PRIO_OPT_O");

                       // sauter l'argument traité
                       nbarg --;
                       varg  ++;
                       break;

            // aucune autre option n'est reconnue
                       // "Option %s incorrecte"
            default  : aff_err_arg ("ERR_OPTION", *varg);
                       nbarg = 0;  // pour rappeller la syntaxe
        }
    }

    // controle du nombre d'arguments restants
    if (nbarg == 1)
    {
        // ouvrir le fichier de configuration
        fconf = ouvre_ficonf (*varg);

        if (fconf)
        {
            // connexion sur le compte mail du serveur pop
            if (connect_pop (fconf))
            {
                // récupérer le nom du répertoire racine de la messagerie
                fgets (fichliste, szchemin, fconf);

                // fabriquer le chemin d'accès au fichier contenant les
                // destinataires interdits : <racine>/refus_dest
                car_fichliste = fichliste + strlen (fichliste);
                *(car_fichliste - 1) = '/';
                strcpy (car_fichliste, ficdir ("FIC_REFUS_DEST"));

                // charger en mémoire les destinataires interdits
                listedest = charge_valchamp (fichliste, &sz_listedest);

                // si la liste n'est pas vide
                if (sz_listedest)
                {
                    // récupération du nombre de mails
                    nbmes = nbmails ();

                    // Initialisation du message à afficher
                    // à chaque analyse de mail
                    // "\rAnalyse du mail n° %d"
                    strcpy (mess_analys, message ("ANALYSE_MAIL"));

                    // vérification des différents mails
                    for (numes = 1; numes <= nbmes; numes++)
                    {
                        // si le destinataire du mail
                        // contient une chaine interdite
                        if (testdest (numes))
                        {
                            // demande de destruction du mail
                            sprintf (bufw, "DELE %d", numes);
                            env_pop (bufw);
                            lire_pop ();
                            supprimes ++;

                            // si utilisation d'un fichier trace
                            if (ftrace)
                                // mémoriser le destinataire de ce mail
                                fprintf (ftrace, "%s%s\n", datecour, bufTo);
                        }
                        else
                            conserves ++;
                    }

                    // édition d'un récapitulatif
                    // "\n%d messages conservés, %d supprimés\n"
                    printf (message ("BILAN_FILTRAGE"), conserves, supprimes);
                }

                // se déconnecter proprement du serveur pop
                deconnect_pop ();

                // si des mails ont été supprimés
                if (supprimes)
                    // attendre pour enregistrement correct des suppressions
                    // (évite problème si autre filtre appelé juste après)
                    sleep (2);
            }

            // on n'a plus besoin du fichier de configuration
            fclose (fconf);
        }
    }
    else
        // "Syntaxe : %s [-(o|O)] [-t fichier_trace] fich_configuration"
        psyntaxe ("SYNT_FILT-DEST/SUJ");

    return (0);
}



/* lit l'entête d'un mail et vérifie si son destinataire est autorisé */

int testdest (int numes)
{
    char bufw [120];     // buffer d'envoi d'une requête
    char destbrut [120]; // buffer contenant le destinataire du mail non décodé
    int  debdest;        // position premier caractère utile du destinataire


    // "\rAnalyse du mail n° %d"
    printf (mess_analys, numes);
    fflush (stdout);

    // initialisation
    bufTo    [0] = '\0';
    destbrut [0] = '\0';

    // demande de lecture de l'entête du message
    sprintf (bufw, "TOP %d 1", numes);
    env_pop (bufw);

    // lire la première ligne de l'entête du message
    lire_pop ();

    // terminé pour ce mail si erreur d'envoi coté serveur
    if (memcmp (buf_lect, "-ERR ", 5) == 0)
    {
        // Erreur serveur pour l'accès au mail
        aff_err_argnum ("ERREUR_SERVEUR", numes);
        return 0;
    }

    // lecture entête du message et mémorisation du destinataire du mail
    do
    {
        // si on a trouvé le champ destinataire
        if (start ("To"))
        {
            // recherche du premier caractère significatif du destinataire
            debdest = 3;

            while (buf_lect [debdest] == ' ')
                debdest++;

            // si option -o ou -O
            if (opto || optO)
            {
                // mémoriser destinataire du mail avant conversion en le
                // tronquant si nécessaire pour éviter un débordement de tableau
                if (strlen (buf_lect + debdest) >= sizeof (destbrut))
                {
                    memcpy (destbrut, buf_lect + debdest, sizeof (destbrut));
                    destbrut [sizeof (destbrut) - 1] = '\0';
                }
                else
                    strcpy (destbrut, buf_lect + debdest);
            }

            // si on n'utilise pas l'option -O
            if (! optO)
            {
                // convertir les caractères spéciaux de la ligne
                majlignentete ();

                // tronquer si nécessaire le destinataire
                if (strlen (buf_lect + debdest) >= sizeof (bufTo))
                     buf_lect [debdest + sizeof (bufTo) - 1] = '\0';

                // mémorisation du destinataire converti
                strcpy (bufTo, buf_lect + debdest);
            }
        }

        // lire la ligne suivante de l'entête du message
        lire_pop ();
    }
    // lecture terminée si ligne limitée à un .
    while (buf_lect [0] != '.' || buf_lect [1] != '\0');

    // vérifier si le mail contient un des destinataires de la liste interdite
    if (optO)
        // option -O : test sur le destinataire brut seulement
        return trouve_valchamp (destbrut, listedest, sz_listedest);
    else if (opto)
    {
        // option -o (seule) : test sur le destinataire brut et converti
        return (trouve_valchamp (destbrut, listedest, sz_listedest)
            ||  trouve_valchamp (bufTo,    listedest, sz_listedest));
    }
    else
        // aucune option : test sur le destinataire converti seulement
        return trouve_valchamp (bufTo, listedest, sz_listedest);
}