/*
    Fichier chargechampok.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 télécharge parmi les mail en attente sur le serveur
    de messagerie, ceux dont un champ choisi contient une chaine de
    caractères autorisée.

    La liste des chaines de caractères autorisée pour ce champ est
    mémorisée dans un fichier.

    Un fichier de configuration est utilisé pour se connecter à la
    boite aux lettres et pour fixer le répertoire racine du système
    de messagerie.

    Les mail entrants sont stockés dans le sous répertoire "entree"
    de ce répertoire racine et se distinguent par leur numéro.
*/


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

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "messages.h"
#include "buflect.h"
#include "ficonf.h"
#include "pop.h"
#include "numail.h"
#include "testchamp.h"
#include "trtentete.h"
#include "szchemin.h"


/* constantes pour indiquer si l'on efface le(s) mail(s) téléchargé(s) */
#define OPTDEFAUT  0
#define EFFACE     1
#define CONSERVE   2


/* prototypes */
int testchamp (int numes, char *nomchamp);
void chargemail (int numes, long numail, int effacement);


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


char **listechamp;        // mémorise les champs interdits
int  sz_listechamp;       // nombre de champs mémorisés dans listechamp
char bufChamp [120];      // buffer contenant le champ du mail à tester
char dirmails [szchemin]; // répertoire de destination des messages

// chaines de caractères mémorisées pour éviter appels répétitifs à message ()
char mess_analys [50]; // message signalant l'analyse d'un mail
char mess_telech [50]; // message signalant le téléchargement d'un mail



/* programme principal */

int main (int nbarg, char *varg[])
{
    FILE *fconf;         // descripteur du fichier de configuration
    char fichliste [szchemin]; // fichier contenant liste des chaines à tester
    char *nomchamp;      // nom du champ à tester
    char *nomfliste;     // nom du fichier contenant les chaines à tester
    int  numes, nbmes;   // numéro du mail courant et nombre de mails
    int  nbrecup = 0;    // nombre de mails téléchargés
    long numail;         // numéro du mail dans le fichier téléchargé
    int  option;  // détermine si on conserve sur le serveur les mails récupérés
    int  i, j;           // compteurs


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

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

    // récupération du nom du champ à tester
    if (nbarg > 1)
    {
        nomchamp = varg [0];
        nbarg --;
        varg ++;
    }

    // initialisations valeur des options
    nomfliste = NULL;
    option = OPTDEFAUT;

    // si le programme a été lancé avec des options
    while (nbarg >= 2 && **varg == '-')
    {
        switch (varg [0][1])
        {
            // option effacement du serveur des mails récupérés
            case 'd': if (option == CONSERVE)
                      {
                          // "Options -d et -k incompatibles"
                          affiche_err ("COMPAT_OPT_DK");
                          return (-1);
                      }
                      else
                          option = EFFACE;

                      break;

            // option conservation sur le serveur des mails récupérés
            case 'k': if (option == EFFACE)
                      {
                          // "Options -d et -k incompatibles"
                          affiche_err ("COMPAT_OPT_DK");
                          return (-1);
                      }
                      else
                          option = CONSERVE;

                      break;

            // option nom du fichier contenant la liste des chaines autorisées
            case 'f' : nomfliste = varg [1];

                       // décompter l'argument supplémentaire traité
                       varg ++;
                       nbarg --;
                       break;

                       // "Option %s incorrecte"
            default  : aff_err_arg ("ERR_OPTION", *varg);
                       nbarg = 0;   // pour afficher la syntaxe de la commande
        }

        // décompter l'argument traité
        varg ++;
        nbarg --;
    }

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

        if (fconf)
        {
            // connexion sur le compte mail du serveur pop
            if (connect_pop (fconf))
            {
                // récupérer le répertoire racine de la messagerie
                fgets (dirmails, sizeof (dirmails) - 7, fconf);
                dirmails [strlen (dirmails) - 1] = '\0';

                // si ce répertoire existe
                if (access (dirmails, 0) == 0)
                {
                    // détermination du nom du fichier
                    // contenant les chaines interdites

                    // cas particulier : chemin d'accès absolu à ce fichier
                    if (nomfliste && *nomfliste == '/')
                        strcpy (fichliste, nomfliste);
                    else
                    {
                        // cas général : pas de chemin d'accès absolu au fichier

                        // on complète ce nom d'un /
                        strcpy (fichliste, dirmails);
                        strcat (fichliste, "/");

                        // si le nom de ce fichier a été passé en paramètre
                        if (nomfliste)
                            // le rajouter au nom du répertoire
                            strcat (fichliste, nomfliste);
                        else
                        {
                            // sinon, on va générer un nom à
                            // partir du nom du champ
                            strcat (fichliste, ficdir ("FIC_ACCEPT_"));

                            i = strlen (fichliste);
                            j = 0;

                            do
                                // le nom du champ est recopié en minuscules
                                fichliste [i++] = tolower (nomchamp [j]);
                            while (nomchamp [j++]);
                        }
                    }

                    // charger en mémoire les champs interdits
                    listechamp = charge_valchamp (fichliste, &sz_listechamp);

                    // si la liste n'est pas vide
                    if (sz_listechamp)
                    {
                        // créer si nécessaire le sous repertoire d'entrée
                        strcat (dirmails, "/");
                        strcat (dirmails, ficdir ("DIR_ENTREE"));
                        mkdir (dirmails, 0755);

                        // récupération du nombre de mails
                        nbmes = nbmails ();

                        // si des mails peuvent être récupérés
                        if (nbmes)
                        {
                            // récupération du numéro du dernier fichier mail
                            numail = num_dermail (dirmails);

                            // Initialisation des messages à afficher à chaque
                            // analyse ou téléchargement de mail

                            // "\rAnalyse du mail n° %d       "
                            strcpy (mess_analys, message ("ANALYSE_MAIL_BL"));

                            // "\rTéléchargement du mail n° %d"
                            strcpy (mess_telech, message ("TELECH_MAIL"));

                            // pour chaque fichier mail du serveur
                            for (numes = 1; numes <= nbmes; numes++)
                            {
                                // si l'expéditeur du mail est autorisé
                                if (testchamp (numes, nomchamp))
                                {
                                    // télécharger le mail correspondant
                                    chargemail (numes, ++numail, option);

                                    // on compte les mails téléchargés
                                    nbrecup ++;
                                }
                            }

                            // édition d'un récapitulatif
                            // "\n%d mails téléchargés sur %d\n"
                            printf (message ("TOTAL_TELECH"), nbrecup, nbmes);

                            // sauvegarde du numéro du dernier fichier mail
                            sauv_num_dermail (dirmails, numail);
                        }
                    }
                }
                else
                    // "répertoire de messagerie %s inexistant"
                    aff_err_arg ("REP_RACINE_ABSENT", dirmails);

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

            // on n'a plus besoin du fichier de configuration
            fclose (fconf);
        }
    }
    else
        // "Syntaxe : %s nom_champ [-f fich_liste] [-(k|d)] fich_configuration"
        psyntaxe ("SYNT_CHARGECHAMPOK");

    // pour faire plaisir à gcc qui veut une fonction main de type int
    return (0);
}




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

int testchamp (int numes, char *nomchamp)
{
    char bufw [120];      // buffer d'envoi d'une requête
    int  i;               // simple compteur


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

    // initialisation
    bufChamp [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 de le champ du mail
    do
    {
        if (start (nomchamp))
        {
            // convertir les caractères spéciaux de la ligne
            majlignentete ();

            // initialisation
            i = strlen (nomchamp) + 1;

            // recherche du début du champ
            while (buf_lect [i] == ' ')
                i++;

            // tronquer si nécessaire le champ (pour éviter un plantage)
            if (strlen (buf_lect + i) > sizeof (bufChamp))
                 buf_lect [i + sizeof (bufChamp) - 1] = '\0';

            // mémorisation du champ
            strcpy (bufChamp, buf_lect + i);
        }

        // 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 champ de la liste interdite
    return trouve_valchamp (bufChamp, listechamp, sz_listechamp);
}



/* télécharge le mail choisi et l'enlève du serveur si c'est demandé */

void chargemail (int numes, long numail, int effacement)
{
    char bufw [120];    // buffer d'envoi d'une requête
    char ficmail [sizeof (dirmails) + 9];
    FILE *fmail;


    // création du fichier mail
    sprintf (ficmail, "%s/r%07ld.n", dirmails, numail);

    fmail = fopen (ficmail, "w");

    if (fmail)
    {
        // message de suivi du déroulement
        // "\rTéléchargement du mail n° %d"
        printf (mess_telech, numes);
        fflush (stdout);

        // demande de lecture du message et réception de l'acquittement
        sprintf (bufw, "RETR %d", numes);
        env_pop (bufw);
        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);
            fclose (fmail);
            unlink (ficmail);
            return;
        }

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

        // lecture et copie du message jusqu'à une ligne limitée a un .
        while (buf_lect [0] != '.' || buf_lect [1] != '\0')
        {
            // copie de la ligne lue dans le fichier mail
            fputs (buf_lect, fmail);
            fputc ('\n', fmail);     // nécessaire car supprimé de buf_lect

            // et lecture de la suivante
            lire_pop ();
        }

        // fermer le fichier contenant le mail
        fclose (fmail);

        // et supprimer si nécessaire le mail du serveur
        if (effacement != CONSERVE)
        {
            sprintf (bufw, "DELE %d", numes);
            env_pop (bufw);
            lire_pop ();
        }
    }
    else
        // "Impossible d'écrire dans le fichier %s"
        aff_err_arg ("IMPOS_ECR_FICH", ficmail);
}