/*
    Fichier repmail.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 prépare une réponse pour le fichier mail passé en paramètre
    Le chemin d'accès au fichier peut être absolu ou relatif.

    A partir du squelette généré, la réponse se fait grace à l'éditeur vi

    Le fichier obtenu est ensuite stoqué dans le répertoire des mails à envoyer
    Pour que cela soit possible, il faut :
    - soit que la commande repmail soit lancée depuis la chaine vmail...
    - soit préciser le nom du répertoire de l'arborescence des mails
*/


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

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "messages.h"
#include "buflect.h"
#include "fmail.h"
#include "encodage.h"
#include "trtentete.h"
#include "trtligne.h"
#include "groupeligne.h"
#include "trtbordure.h"
#include "trtsection.h"
#include "numail.h"
#include "genentete.h"
#include "modepage.h"
#include "carspe.h"


#define  szbuf    160   // taille des tableaux mémorisant les champs de l'entête


/* prototypes */
void gene_entete (char *nomfic);
void gene_enteterep (char *nomfic);
void gene_mesrep ();
void copie_texte ();
void aff_debliste (long pos_deblig);
void copchamp (long pos_deblig, int conversion);
void genligne (char *buffer);


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


long numail; // numéro que prendra le mail généré
// caractère signifcatif de la variable d'environnement libremail_xorig
char xorig;


/* programme principal */

int main (int nbarg, char *varg[])
{
    char ficmail [szchemin];  // fichier mail de réponse
    char fentete [szchemin];  // fichier contenant l'entete du message
    char commande [szchemin]; // commande d'appel de l'éditeur
    char *editeur;            // éditeur utilisé pour saisir la réponse
    char *varenv_xorig;       // variable d'environnement libremail_xorig


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

    // si nombre d'arguments correct
    if (--nbarg == 1 || nbarg == 2)
    {
        // ouvrir le fichier mail auquel on doit répondre
        fmail = fopen (varg [1], "r");

        // terminé si le fichier n'a pas pu être ouvert
        if (! fmail)
        {
            if (access (varg [1], 0) == 0)
                // "Problème d'accès au fichier %s"
                errfatale ("ACCES_FICHIER", varg [1]);
            else
                // "Fichier %s inexistant"
                errfatale ("FICH_INEXISTANT", varg [1]);
        }
    }
    // sinon, rappel de la syntaxe de la commande
    else
        // "Syntaxe : %s nom_fichier_mail [répertoire_emails]"
        psyntaxe ("SYNT_REP/TRSF-MAIL");

    // récupérer la partie significative de la variable libremail_xorig
    varenv_xorig = getenv ("libremail_xorig");

    if (varenv_xorig)
        xorig = tolower (*varenv_xorig);
    else
        xorig = '\0';

    // passer en mode standard pour les lectures au clavier
    mode_normal ();

    // récupérer le nom du répertoire des mails à envoyer
    recupdirenv (nbarg, varg [2]);

    // créer un nom de fichier temporaire pour l'entête du mail
    // il a toujours le même nom pour éviter de polluer le
    // répertoire d'envoi en cas de fausse manoeuvre opérateur (^C)
    sprintf (fentete, "%s/tmp-ent", direnv);

    // fabriquer l'entête du mail de réponse
    gene_entete (fentete);

    // créer un nom de fichier temporaire pour le message
    sprintf (ficmail, "%s/tmp-mes", direnv);

    // fabriquer le message de réponse
    gene_enteterep (ficmail);

    // Choix de l'éditeur de textes
    editeur = getenv ("EDITOR");

    if (! editeur)
        editeur = "vi";

    // c'est au tour de l'utilisateur de répondre au mail
    sprintf (commande, "%s %s", editeur, ficmail);
    system (commande);

    // mémoriser les dates et heure d'envoi du message
    ajout_date (fentete);

    // on va regrouper l'entête et le message dans un fichier numéroté définitif
    fusionner (fentete, numail, ficmail);

    // mettre à jour le fichier numail du répertoire de sortie
    sauv_num_dermail (direnv, numail);

    // ajouter la signature au message, si elle existe
    ajout_sign (ficmail);

    // modification avant envoi ?
    // "Voulez vous modifier le fichier complet avant envoi ? "
    affiche_msg_nocr ("MAJ_MAIL_PRET");

    if (tolower (getchar ()) != 'n')
    {
        // si oui, appeler l'éditeur
        sprintf (commande, "%s %s", editeur, ficmail);
        system (commande);
    }

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


/* lit l'entête du message choisi et fabrique celle de la réponse */

void gene_entete (char *nomfic)
{
    long pos_deblig;  // position dans le fichier en début de ligne courante
    // position dans le fichier des champs pouvant tenir sur plusieurs lignes
    long posTo = -1, posCc = -1, posSubject = -1, posRef = -1;
    // mémorisation directe d'autres champs
    // grosse taille des buffers pour ne pas tronquer une adresse
    // de type confirmation d'inscription à une mailing list
    char bufFrom [szbuf], bufXorig [szbuf], bufReply [szbuf], bufMesid [szbuf];
    char *bufexped;       // pour traitement commun de bufFrom et bufXorig;
    char reponse [10];    // réponse à une question
    int  choix, choixmax; // choix des destinataires
    int  i, j;            // compteurs


    // fabriquer et ouvrir en écriture le fichier d'entête
    fdest = fopen (nomfic, "w");

    if (! fdest)
        // "Impossible de créer un fichier d'entête %s"
        errfatale ("IMPOS_CRE_ENTETE", nomfic);

    // initialisation
    *bufFrom    = '\0';
    *bufXorig   = '\0';
    *bufReply   = '\0';
    *bufMesid   = '\0';

    // lecture et mémorisation de l'entête du message
    do
    {
        // récupérer la position en début de ligne
        pos_deblig = ftell (fmail);

        // lire une ligne de l'entête du message
        lire_fmail ();

        // pour éviter un débordement de buffer lors d'une copie
        buf_lect [szbuf - 1] = '\0';

        // repérage des champs importants et mémorisation
        // de leur contenu ou de leur position
        if (start ("From") || (start ("X-Original-From") && xorig != 'n'))
        {
            // initialiser bufexped avec bufFrom ou bufXorig
            if (toupper (*buf_lect) == 'F')
                bufexped = bufFrom;
            else
                bufexped = bufXorig;

            // convertir les caractères spéciaux éventuels
            majlignentete ();

            // analyse et copie dans le bufFrom
            // on n'utilise pas memconvbuf parce qu'il tronque à 80 caractères
            i = 0;
            j = 0;

            do
            {
                // recopier un caractère
                bufexped [i] = buf_lect [i];

                // mémoriser la présence d'une adresse Email dans la ligne
                if (buf_lect [i] == '@')
                    j = i;
            }
            while (buf_lect [i++]);

            // si aucune adresse email valide n'a été trouvée dans la ligne
            if (buf_lect [j] != '@')
            {
                // lire la ligne suivante
                lire_fmail ();

                // convertir les caractères spéciaux éventuels
                majlignentete ();

                // et copie dans le buffer à la suite de la ligne précédente
                j = 0;
                i --;

                while (buf_lect [j] && i < szbuf - 1)
                {
                    // recopier un caractère et passer au suivant
                    bufexped [i++] = buf_lect [j++];
                }

                // terminer la chaine de caractères
                bufexped [i] = '\0';
            }
        }
        else if (start ("To"))
            posTo = pos_deblig;      // on mémorise la position de la ligne
        else if (start ("Cc"))
            posCc = pos_deblig;      // on mémorise la position de la ligne
        else if (start ("Reply-To"))
        {
            // pas de conversion des lignes contenant une adresse Email
            // (on évite ainsi de supprimer les _ de certaines adresses)
            strcpy (bufReply, buf_lect);
        }
        else if (start ("Subject"))
            posSubject = pos_deblig; // on mémorise la position de la ligne
        else if (start ("Message-Id"))
        {
            // on récupère juste la valeur du Message-Id sans conversion
            // elle servira à générer les champs In-Reply-To et Reference
            if (buf_lect [11] == ' ')
                strcpy (bufMesid, buf_lect + 12);
            else
                strcpy (bufMesid, buf_lect + 11);
        }
        else if (start ("Reference"))
            posRef = pos_deblig;      // on mémorise la position de la ligne
    }
    while (buf_lect [0] != '\0');  // lecture entête terminée si ligne vide

    // récupérer l'adresse de celui qui répond au mail
    lire_exped ();

    // chercher le numéro du mail que l'on va créer
    numail = num_dermail (direnv) + 1;

    // génération du champ Message-Id
    gen_mes_id (fdest, numail, buf_lect);

    // mettre l'expéditeur du message
    ajouts = 0;
    ajout_adr (buf_lect, "From");
    fputc ('\n', fdest);

    // choix des destinataires
    // pas de sélection manuelle des adresses, mais jusqu'à 6 choix
    // en fonction des caractéristiques du mail auquel on répond
    // "\nRépondre à :\n"
    affiche_msg ("CHOIX_REP-0");

    // si le champ X-Original_From est présent dans le mail
    if (*bufXorig)
    {
        // "1) Le vrai expéditeur :%s\n\n"
        // "2) Le vrai expéditeur + celui qui répond en copie : %s\n\n"
        // "3) Le vrai expéditeur + destinataires en copie à choisir\n"
        printf (message ("CHOIX_REP-1A"), bufXorig + 16);
        printf (message ("CHOIX_REP-2A"), buf_lect);
        affiche_msg ("CHOIX_REP-3A");
    }
    // sinon (le champ From contient l'expéditeur)
    else
    {
        // "1) L'expéditeur :%s\n\n"
        // "2) L'expéditeur + celui qui répond en copie : %s\n\n"
        // "3) L'expéditeur + destinataires en copie à choisir\n"
        printf (message ("CHOIX_REP-1"), bufFrom + 5);
        printf (message ("CHOIX_REP-2"), buf_lect);
        affiche_msg ("CHOIX_REP-3");
    }

    // "4) Au(x) destinataire(s) principal/aux"
    affiche_msg ("CHOIX_REP-4");

    // cette liste peut tenir sur plusieurs lignes
    aff_debliste (posTo);
    putchar ('\n');

    // 2 libellés également pour le choix 5
    if (*bufXorig)
        // "5) Le vrai expéditeur + destinataire(s) principal/aux"
        affiche_msg ("CHOIX_REP-5A");
    else
        // "5) L'expéditeur + destinataire(s) principal/aux"
        affiche_msg ("CHOIX_REP-5");

    // ces choix ne sont rajoutés que s'ils sont possibles
    if (*bufReply)
    {
        // "6) A l'adresse pour répondre :%s\n"
        // "7) A l'adresse pour répondre + celui qui répond en copie\n\n"
        putchar ('\n');
        printf (message ("CHOIX_REP-6"), bufReply + 9);
        putchar ('\n');
        affiche_msg ("CHOIX_REP-7");
        choixmax = 7;
    }
    else
        choixmax = 5;

    if (*bufXorig)
    {
        // "8) L'expéditeur falsifié :%s\n\n"
        // "9) L'expéditeur falsifié + destinataires en copie à choisir\n"
        printf (message ("CHOIX_REP-8"), bufFrom + 5);
        affiche_msg ("CHOIX_REP-9");
        choixmax = 9;
    }

    // choix opérateur
    do
    {
        // "Votre choix ? "
        putchar ('\n');
        affiche_msg_nocr ("VOTRE_CHOIX");
        fgets (reponse, sizeof (reponse), stdin);
        choix = atoi (reponse);
    }
    while (choix < 1 || choix > choixmax);

    // génération de la liste des destinataires principaux
    // (sauf pour le choix 4)
    switch (choix)
    {
        case 1 :
        case 2 :
        case 3 :
        case 5 : // expéditeur ou vrai expéditeur
                 if (*bufXorig)
                     fprintf (fdest, "To:%s", bufXorig + 16);
                 else
                     fprintf (fdest, "To:%s", bufFrom + 5);

                 // terminer la ligne pour les choix 1 à 3
                 if (choix != 5)
                     fputc ('\n', fdest);
                 break;

        case 6 :
        case 7 : // adresse pour répondre
                 fprintf (fdest, "To:%s\n", bufReply + 9);
                 break;

        case 8 :
        case 9 : // expéditeur falsifié
                 fprintf (fdest, "To:%s\n", bufFrom + 5);
                 break;
    }

    // génération de la liste des destinataires en copie
    // (ou destinataire principaux pour choix 4 et 5)
    switch (choix)
    {
        case 2 :
        case 7 : // celui qui répond en copie
                 lire_exped ();
                 ajouts = 0;
                 ajout_adr (buf_lect, "Cc");
                 fputc ('\n', fdest);
                 break;

        case 3 :
        case 9 : // destinataires en copie à choisir
                 // charger le carnet d'adresses
                 charge_carnet_adr ();

                 // configurer la liaison clavier
                 // pour lecture directe avec timeout
                 mode_raw ();

                 // et choisir des destinataires
                 choixdest ("Cc");

                 // on repasse en mode saisie normale
                 mode_normal ();
                 break;

        case 4 :
        case 5 : // destinataires principaux
                 // se positionner sur le champ à copier
                 fseek (fmail, posTo, SEEK_SET);

                 // lire et copier la première ligne
                 lire_fmail ();

                 // en tenant compte éventuellement de la ligne précédente
                 if (choix == 4)
                     fputs (buf_lect, fdest);
                 else
                     fprintf (fdest, ",\n\t%s", buf_lect + 4);

                 // tester la ligne suivante
                 lire_fmail ();

                 // recopier jusqu'à la fin de la liste
                 while (*buf_lect == ' ' || *buf_lect == '\t')
                 {
                     fprintf (fdest, "\n%s", buf_lect);
                     lire_fmail ();
                 }

                 // terminer proprement la liste des destinataires
                 fputc ('\n', fdest);

                 // rajout à la demande des destinataires en copie
                 // à la suite de la liste des destinataires principaux
                 if (posCc >= 0 && (choix == 4 || choix == 5))
                 {
                     // "\nDestinataires en copie :"
                     affiche_msg ("AJOUT_DESTCOP-1");
                     aff_debliste (posCc);

                     // "Voulez vous les rajouter ? "
                     affiche_msg_nocr ("AJOUT_DESTCOP-2");
                     fgets (reponse, sizeof (reponse), stdin);

                     // traitement réponse valable en de nombreuses langues
                     // si la réponse ne commence pas par 'n', c'est oui
                     // (ceux qui obligent à répondre 'y' sont de gros nuls)
                     if (tolower (*reponse) != 'n')
                     {
                         // se positionner sur le champ à copier
                         fseek (fmail, posCc, SEEK_SET);

                         // lire la première ligne
                         lire_fmail ();

                         // copier jusqu'à la fin de la liste
                         do
                         {
                             fprintf (fdest, "%s\n", buf_lect);
                             lire_fmail ();
                         }
                         while (*buf_lect == ' ' || *buf_lect == '\t');
                     }
                 }
                 break;
    }

    // génération du champ Subject
    if (posSubject >= 0)
    {
        // lire la ligne contenant le sujet
        fseek (fmail, posSubject, SEEK_SET);
        lire_fmail ();

        // convertir les caractères spéciaux éventuels
        // c'est dans envmail qu'on réencodera éventuellement ce champ
        majlignentete ();

        // si la ligne du sujet n'est pas vide
        if (strlen (buf_lect) > 9)
        {
            // si le sujet du mail commence par les lettres re
            if (tolower (buf_lect [9]) == 'r' && tolower (buf_lect [10]) == 'e')
            {
                // si le sujet commence par Re: , RE: , re: etc...
                if (buf_lect [11] == ':')
                    // On utilise la syntaxe la plus courante Re:
                    fprintf (fdest, "Subject: Re:%s", buf_lect + 12);

                // sinon si le sujet commence par Re : , RE : , re : etc...
                else if (buf_lect [11] == ' ' && buf_lect [12] == ':')
                    // on supprime le blanc avant le :
                    fprintf (fdest, "Subject: Re:%s", buf_lect + 13);

                // sinon (les lettres re ne sont pas suivies d'un :
                else
                    // on rajoute un Re: en début de sujet
                    fprintf (fdest, "Subject: Re: %s", buf_lect + 9);
            }
            // sinon
            else
                // on rajoute un Re: en début de sujet
                fprintf (fdest, "Subject: Re: %s", buf_lect + 9);

            // lire la ligne suivante
            lire_fmail ();
        }
        else
        {
            // on va vérifier si le sujet est sur la ligne suivante
            lire_fmail ();

            // le libellé du sujet dépendra du résultat du test
            if (*buf_lect == ' ' || *buf_lect == '\t')
                fputs ("Subject: Re: ", fdest);
            else
            {
                // "Subject: Réponse à message sans objet précisé"
                fputs (message ("SUJET_VIDE"), fdest);
            }
        }

        // tantque c'est aussi une ligne du sujet
        while (*buf_lect == ' ' || *buf_lect == '\t')
        {
            // convertir les caractères spéciaux éventuels
            majlignentete ();

            // rajouter le contenu de la ligne au sujet
            fputs (buf_lect + 1, fdest);

            // et lire la ligne suivante
            lire_fmail ();
        }

        // terminer la ligne contenant le sujet
        fputc ('\n', fdest);
    }
    else
    {
        // "Subject: Réponse à message sans objet précisé"
        fputs (message ("SUJET_VIDE"), fdest);
        fputc ('\n', fdest);
    }

    // si le mail auquel on répond avait un identificateur
    if (*bufMesid)
    {
        // on va générer le champ Reference

        // s'il y avait déjà un champ Reference
        if (posRef >= 0)
        {
            // se positionner sur ce champ
            fseek (fmail, posRef, SEEK_SET);

            // lire la première ligne
            lire_fmail ();

            // copier jusqu'à la fin de la liste
            do
            {
                fprintf (fdest, "%s\n", buf_lect);
                lire_fmail ();
            }
            while (*buf_lect == ' ' || *buf_lect == '\t');

            // rajouter la dernière référence
            fprintf (fdest, "           %s\n", bufMesid);
        }
        // sinon
        else
            // créer un champ référence
            fprintf (fdest, "Reference: %s\n", bufMesid);

        // générer le champ In-Reply-To
        fprintf (fdest, "In-Reply-To: %s\n", bufMesid);
    }

    // jeu de caractères du message
    fprintf (fdest, "Content-Type: text/plain; charset=");

    if (util_utf8 ())
        fprintf (fdest, "UTF-8;\n");
    else
        fprintf (fdest, "ISO-8859-15;\n");

    // mode d'encodage
    fprintf (fdest, "Content-Transfer-Encoding: 8bit\n");

    // variante (qui suppose des conversions avant envoi du mail)
    // fprintf (fdest, "Content-Transfer-Encoding: quoted-printable\n");

    // un copyright qui n'est pas celui d'Outlook ;-))
    // "libremail : logiciel libre multilingue"
    fprintf (fdest, "User-Agent: libremail : %s\n",
                     message ("QUALIF_LIBREMAIL"));

    // permettra de relire ce fichier
    fclose (fdest);
}



/* lit le message choisi et fabrique le squelette de la réponse
   cette fonction traite essentiellement l'entête du mail
   puis appelle gene_mesrep pour le rajout du corps du mail */


void gene_enteterep (char *nomfic)
{
    long pos_deblig;  // position dans le fichier en début de ligne
    // position dans le fichier mail des principaux champs de l'entête
    long posDate, posFrom, posXorig, posTo, posCc, posReply,
         posSubject, posContent, posUseAgent;


    // fabriquer et ouvrir en écriture le fichier mail
    fdest = fopen (nomfic, "w");

    if (! fdest)
        // "Impossible de créer le fichier mail %s"
        errfatale ("IMPOS_CRE_FICMAIL", nomfic);

    // initialisation
    posDate     = -1;
    posFrom     = -1;
    posXorig    = -1;
    posTo       = -1;
    posCc       = -1;
    posReply    = -1;
    posSubject  = -1;
    posContent  = -1;
    posUseAgent = -1;

    // on revient au début du fichier mail
    rewind (fmail);

    // lecture de l'entête et mémorisation de la position des champs importants
    do
    {
        // récupérer la position en début de ligne
        pos_deblig = ftell (fmail);

        // lire une ligne de l'entête du message
        lire_fmail ();

        // repérage des champs importants et mémorisation de leur position
        if (start ("X-Mailer") || start ("User-Agent"))
            posUseAgent = pos_deblig;
        else if (start ("Date"))
            posDate = pos_deblig;
        else if (start ("From"))
            posFrom = pos_deblig;
        else if (start ("X-Original-From") && xorig != 'n')
            posXorig = pos_deblig;
        else if (start ("To"))
            posTo = pos_deblig;
        else if (start ("Cc"))
            posCc = pos_deblig;
        else if (start ("Reply-To"))
            posReply = pos_deblig;
        else if (start ("Subject"))
            posSubject = pos_deblig;
        else if (start ("Content-Type"))
            posContent = pos_deblig;
        else if (start ("Content-Transfer-Encoding"))
            mem_encodage ();
    }
    while (buf_lect [0] != '\0');  // lecture entête terminée si ligne vide

    // sauter des lignes pour réponse avant le message
    fputc ('\n', fdest);
    fputc ('\n', fdest);

    // rappel des caractéristiques du message auquel on répond
    if (posUseAgent >= 0)
        copchamp (posUseAgent, 0);
    if (posDate >= 0)
        copchamp (posDate, 0);
    if (posFrom >= 0 && (posXorig < 0 || xorig == '2'))
        copchamp (posFrom, 1);
    if (posXorig >= 0)
        copchamp (posXorig, 1);
    if (posTo >= 0)
        copchamp (posTo, 1);
    if (posCc >= 0)
        copchamp (posCc, 1);
    if (posReply >= 0)
        copchamp (posReply, 1);
    if (posSubject >= 0)
        copchamp (posSubject, 1);

    // récupérer le type principal du message et ses caractéristiques
    recup_typeorig (posContent);

    // revenir au début du corps du message
    fseek (fmail, pos_deblig, SEEK_SET);
    lire_fmail ();

    // copie du contenu du mail
    if (ctypeorig & Multipart)
        // il faudra analyser les sections
        gene_mesrep ();
    else
        // une simple copie du texte suffit
        copie_texte ();

    // génération automatique terminée
    fclose (fdest);
}


/* affiche les premières lignes d'une liste de destinataires
   (champs To: ou Cc:) du message auquel on répond */


void aff_debliste (long pos_deblig)
{
    int i; // compteur

    // se positionner sur le champ à afficher
    fseek (fmail, pos_deblig, SEEK_SET);

    // lire et afficher la première ligne
    lire_fmail ();
    majlignentete ();
    printf ("  ");
    puts (buf_lect + 3);

    // tester la ligne suivante
    lire_fmail ();
    i = 0;

    // et continuer l'affichage si nécessaire
    while ((*buf_lect == ' ' || *buf_lect == '\t') && ++i < 9)
    {
        majlignentete ();
        printf ("   ");
        puts (buf_lect + 1);
        lire_fmail ();
    }

    // on abrège l'affichage si la liste est trop longue
    if (i >= 9)
        puts ("   (...)");
}


/* recopie un champ de l'entête d'une ou plusieurs lignes
   repéré à partir de sa position dans le fichier mail */


void copchamp (long pos_deblig, int conversion)
{
    // se positionner sur la ligne contenant le champ
    fseek (fmail, pos_deblig, SEEK_SET);

    // lire cette ligne
    lire_fmail ();

    // répéter
    do
    {
        // interpréter si nécessaire les caractères spéciaux
        if (conversion)
            majlignentete ();

        // et afficher la ligne
        fprintf (fdest, "> %s", buf_lect);

        // en tenant compte d'un éventuel \n dans le buffer
        if (buf_lect [strlen (buf_lect) - 1] != '\n')
            fputc ('\n', fdest);

        // lire la ligne suivante
        lire_fmail ();
    }
    // jusqu'à la dernière ligne du champ
    while (*buf_lect == ' ' || *buf_lect == '\t');
}


/* lecture et copie du contenu d'un mail en mode multipart */

void gene_mesrep ()
{
    // mémorisation des modes multipart trouvés
    int multipmixed = 0, multipalter = 0, multiprel = 0, multiprep = 0;


    // mémoriser tous les modes multipart imbriqués
    do
    {
        switch (ctype)
        {
            case MultipMixed : multipmixed = 1;
                               break;

            case MultipAlter : multipalter = 1;
                               break;

            case MultipRep   : multiprep   = 1;
                               break;

            case MultipRel   : multiprel   = 1;
        }

        // passer à la section suivante
        prochaine_section ();

        // récupérer ses caractéristiques
        recup_infos_section ();
    }
    while ((ctype & Multipart) && lire_fmail ());

    // indiquer si le mail peut contenir des pièces jointes
    if (multipmixed)
        // "Pièce(s) jointes(s) probable(s)"
        genligne (message ("PJ_PROBABLE"));

    // si une section multipart/alternative a été trouvée, se positionner
    // (si l'on n'y est pas) sur la section text/plain du mail
    if (multipalter)
        posit_texte ();

    // générer une ligne de séparation avec l'entête
    genligne ("\n");

    // si structure du mail non conforme, message d'erreur
    if (! lire_fmail ())
        // "Pas de zone texte dans ce mail !!!"
        genligne (message ("MANQUE_ZONE_TEXTE"));

    // lecture et mémorisation du corps du message
    do
    {
        // mise en forme et mémorisation de la dernière ligne lue
        majligne ();

        if (buf_lect [strlen (buf_lect) - 1] != '\n')
            regroupeligne (buf_lect);
        else
            genligne (buf_lect);

        // et lecture de la suivante
        if (! lire_fmail ())
            return;   // on sort en fin de fichier

        // si mode multipart/report, on saute les entêtes de section
        if (multiprep && nbordures && surbordure ())
        {
            do
                lire_fmail ();
            while (*buf_lect);
        }
    }
    // on s'arrête en fin de fichier, ou sur la prochaine bordure
    while (nbordures == 0 || ! surbordure ());

    // si mode multipart mixed on va lister les pièces jointes
    if (ctypeorig == MultipMixed)
        liste_pj ();
}



/* lecture et copie d'un mail de type text/plain */

void copie_texte ()
{
    // si texte encodé base 64
    if (encodage_texte == Base64)
        // générer une ligne de séparation avec l'entête
        genligne ("\n");

    // répéter
    do
    {
        // mise en forme de la dernière ligne lue
        majligne ();

        // mémorisation de cette ligne
        if (buf_lect [strlen (buf_lect) - 1] != '\n')
            regroupeligne (buf_lect);
        else
            genligne (buf_lect);

        // et lecture de la suivante
    }
    // on s'arrête en fin de fichier
    while (lire_fmail ());
}



/* mémorise une ligne du mail */

void genligne (char *buffer)
{
    char * nouvligne;
    int  taille_ligne;
    int  i;


    // récupérer la longueur de la ligne
    taille_ligne = strlen (buffer);

    // si ligne longue
    if (taille_ligne > 80)
    {
        // on tente de la tronquer à moins de 80 car
        i = 70;

        // chercher un blanc pour passer à la ligne
        // ou un \n résultant d'un abus de l'encodage Mime
        while (i > 0 && buffer [i] != ' ' && buffer [i] != '\n')
            i--;

        // si pas de blanc trouvé
        if (i == 0)
        {
            // on en cherche un dans l'autre sens
            i = 70;

            while (i < taille_ligne && buffer [i] != ' ' && buffer [i] != '\n')
                i++;
        }

        // mémoriser la taille de la ligne tronquée
        taille_ligne = i;
    }

    // tenir compte d'un '\n' éventuel en cours de ligne !
    // (dans le cas d'un encodage quoted-printable non conforme
    // ou d'un encodage base64)
    for (i = 0; i < taille_ligne - 1; i++)
        if (buffer [i] == '\n')
            taille_ligne = i;

    // recopier les données dans ce tableau
    fputc ('>', fdest);

    if (taille_ligne > 1)
        fputc (' ', fdest);

    for (i = 0; i < taille_ligne; i++)
        fputc (buffer [i], fdest);

    // si la ligne a été tronquée
    if (taille_ligne < strlen (buffer))
    {
        // générer un passage à la ligne
        fputc ('\n', fdest);

        // et traiter la suite
        genligne (buffer + taille_ligne + 1);
    }
}