/*
    Fichier chargepartiel.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 l'un des champs contient (ou ne contient
    pas) une chaine de caractères particulière.

    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 <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 "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 (char *nomchamp, char *chainetest, int numes);
void chargemail (int numes, long numail, int effacement);


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


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
    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;       // option : détermine si on conserve les mails récupérés
    int  optn;         // option : mail récupéré si la chaine n'est pas
                       //          trouvée dans le champ ou si champ absent
    char *ncom;        // nom de la commande que l'on exécute (chargepartiel)


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

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

    // options de fonctionnement par défaut
    option = OPTDEFAUT;
    optn = 0;

    // récupération de l'option de fonctionnement éventuelle
    while (nbarg > 0 && **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 récupération du mail si chaine non trouvée
            case 'n': optn = 1;
                      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 == 3)
    {
        // ouvrir le fichier de configuration
        fconf = ouvre_ficonf (varg [2]);

        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)
                {
                    // 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 le champ à tester contient la chaine
                            // ou ne la contient pas si option -n
                            if (testchamp (varg [0], varg [1], numes) != optn)
                            {
                                // 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 [(-k|d)] [-n] nom_champ chaine_champ fichier_configuration"
        psyntaxe ("SYNT_CHARGEPARTIEL");

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



/* vérifie si le champ nomchamp du mail de numéro numes
   contient la chaine passée en 2ème paramètre */


int testchamp (char *nomchamp, char *chainetest, int numes)
{
    char bufw [120];     // buffer d'envoi d'une requête
    char valchamp [120]; // contenu du champ à tester
    int  poschamp;       // positionnement dans valchamp
    int  i;              // positionnement dans chainetest


    // initialisation
    valchamp [0] = '\0';

    // message de suivi de déroulement
    // "\rAnalyse du mail n° %d       "
    printf (mess_analys, numes);
    fflush (stdout);

    // 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 et mémorisation des caractéristiques du message
    do
    {
        // si elle contient le champ recherché
        if (start (nomchamp))
        {
            // convertir les caractères spéciaux
            majlignentete ();

            // et mémoriser ce champ
            membuf (valchamp);
        }

        // 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');

    // on se positionne au début du champ à tester
    poschamp = 0;

    // vérifier si la chaine chainetest se trouve dans valchamp
    do
    {
        i = 0;

        while (valchamp [poschamp+i] == chainetest [i])
            // terminé si tous les caractères de chainetest trouvés
            if (chainetest [++i] == 0)
                return 1;
    }
    // sinon recherche dans la suite de valchamp
    while (valchamp [poschamp++]);

    // aucune des chaines de la liste n'a été trouvée dans valchamp
    return (0);
}



/* télécharge le message 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);
}