/*
    Fichier voirfmail.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 affiche le contenu d'un fichier mail passé en paramètre
    Le chemin d'accès au fichier peut être absolu ou relatif
*/


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

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "messages.h"
#include "buflect.h"
#include "fmail.h"
#include "encodage.h"
#include "trtentete.h"
#include "trtligne.h"
#include "trtbordure.h"
#include "trtsection.h"


/* prototypes */
void aff_entete ();
void affchamp (long pos_deblig, int conversion);
void aff_corpsmail ();
void aff_mail ();
void aff_texte ();
void genligne (char *chaine);


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


// options d'affichage
int opthb; // de la section text/html au lieu de text/plain
int optT;  // affichage partiel de l'entête pour les traductions

int lig_nonvide; // présence de caractères significatifs dans la ligne


/* programme principal */

int main (int nbarg, char *varg[])
{
    // récupération du nom de l'exécutable
    memcom (*varg);

    // pas encore d'option mémorisée
    opthb = 0;
    optT  = 0;

    // traitement des options éventuelles de la commande
    while (--nbarg > 1 && varg [1][0] == '-')
    {
        // si option -h ou -H
        if ((varg [1][1] | 0x20) == 'h')
        {
            // mémoriser cette option
            if (varg [1][1] == 'h')
                opthb = opthb | 1;
            else
                opthb = opthb | 3;
        }
        // sinon si option -b ou -B
        else if ((varg [1][1] | 0x20) == 'b')
        {
            // mémoriser cette option qui inclue -h ou -H
            if (varg [1][1] == 'b')
                opthb = opthb | 5;
            else
                opthb = 7;
        }
        // sinon, prendre en compte l'option -T
        else if (varg [1][1] == 'T')
            optT = 1;

        // sinon, option incorrecte
        else
            // "Syntaxe : %s [-(h|H|b|B)] [-T] nom_fichier_mail"
            psyntaxe ("SYNT_VOIRFMAIL");

        // un argument traité
        varg ++;
    }

    // controle du nombre d'arguments
    if (nbarg == 1)
    {
        // ouvrir le fichier mail
        fmail = fopen (varg [1], "r");

        // si le fichier a pu être ouvert
        if (fmail)
        {
            // afficher l'entête du mail
            aff_entete ();

            // afficher son contenu
            aff_corpsmail ();

            // et fermer le fichier mail
            fclose (fmail);
        }
        else
            // "Fichier %s non trouvé"
            aff_err_arg ("FICH_ABSENT", varg [1]);
    }
    else
        // "Syntaxe : %s [-(h|H)] [-T] nom_fichier_mail"
        psyntaxe ("SYNT_VOIRFMAIL");

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


/* lit l'entête du message choisi et l'affiche */

void aff_entete ()
{
    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;
    char *varenv_xorig; // variable d'environnement libremail_xorig
    char xorig;         // information utile de libremail_xorig


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

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

    // 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

        // Le premier champ est un peu pour le fun
        if ((start ("X-Mailer") || start ("User-Agent")) && ! optT)
            puts (buf_lect);      // le mailer est affiché directement
        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

    // si mode de fonctionnement standard
    if (! optT)
    {
        // affichage ordonné des champs principaux de l'entête
        if (posDate >= 0)
            affchamp (posDate, 0);
        if (posFrom >= 0 && (posXorig < 0 || xorig == '2'))
            affchamp (posFrom, 1);
        if (posXorig >= 0)
            affchamp (posXorig, 1);
        if (posTo >= 0)
            affchamp (posTo, 1);
        if (posCc >= 0)
            affchamp (posCc, 1);
        if (posReply >= 0)
            affchamp (posReply, 1);
        if (posSubject >= 0)
            affchamp (posSubject, 1);
    }
    // sinon affichage réduit au sujet sans le nom de ce champ
    else if (posSubject >= 0)
        affchamp (posSubject + 8, 1);

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

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


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


void affchamp (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
        printf ("%s", buf_lect);

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

        // lire la ligne suivante
        lire_fmail ();
    }
    // jusqu'à ce qu'on ait traité tout le champ
    while (*buf_lect == ' ' || *buf_lect == '\t');
}


/* lit le corps du message choisi et l'affiche */

void aff_corpsmail ()
{
    // sauter la ligne blanche entre l'entête et le corps du mail
    lire_fmail ();

    // affichage du contenu du mail
    if (ctypeorig & Multipart)
        // il faudra analyser les sections
        aff_mail ();
    else
        // un affichage simple suffit
        aff_texte ();
}


/* suppression des balises html et affichage du reste */

void filtre_balhtm ()
{
    // supprimer les balises html
    sup_balhtm ();

    // réduit à un les blancs multiples et les supprime en fin de ligne
    sup_multiblancs ();

    // et convertir les caractère sous la forme &...;
    conv_carhtm ();

    // si la dernière ligne lue n'est pas vide
    if (*buf_lect && *buf_lect != '\n')
    {
        // l'afficher
        printf ("%s", buf_lect);

        // et mémoriser le fait qu'elle n'est pas vide
        lig_nonvide = 1;
    }
    // sinon si la précédente n'était pas vide ou pas d'option -H
    else if (lig_nonvide)
    {
        // l'afficher
        putchar ('\n');

        // et mémoriser le fait qu'elle est vide
        lig_nonvide = 0;
    }
}


/* affichage du contenu d'un mail en mode multipart */

void aff_mail ()
{
    // 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)"
        affiche_msg ("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 ou text/html du mail
    if (multipalter)
    {
        if (opthb)
            posit_texthtm ();
        else
            posit_texte ();
    }

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

    // si structure du mail non conforme, message d'erreur
    if (! lire_fmail ())
    {
        if (opthb)
            // "Pas de zone texte html dans ce mail !!!"
            affiche_msg ("MANQUE_ZONE_HTML");
        else
            // "Pas de zone texte dans ce mail !!!"
            affiche_msg ("MANQUE_ZONE_TEXTE");
    }

    // si on doit supprimer la partie html avant <body
    if (opthb & 4)
        // le mémoriser
        avantbody = 1;

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

        // si on est dans l'entête html qu'on doit supprimer
        if (avantbody)
            // le faire
            supavantbody ();

        // si option de suppression des balises html
        if (opthb & 2)
            // les supprimer
            filtre_balhtm ();

        // sinon afficher simplement la ligne
        else
            printf ("%s", 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 ())
        {
            // aller à la prochaine ligne vide
            while (lire_fmail () && *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 affichage d'un mail de type text/plain */

void aff_texte ()
{
    // si le mail est au format text/plain
    if (ctypeorig == TextPlain)
        // on ne traitera pas les balises html
        opthb = 0;

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

    // si on doit supprimer la partie html avant <body
    if (opthb & 4)
        // le mémoriser
        avantbody = 1;

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

        // si on est dans l'entête html qu'on doit supprimer
        if (avantbody)
            // le faire
            supavantbody ();

        // si option de suppression des balises html
        if (opthb & 2)
            // les supprimer
            filtre_balhtm ();

        // sinon afficher simplement la ligne
        else
            printf ("%s", buf_lect);

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



/* pour compatibilité avec la bibliothèque trtsection */

void genligne (char *chaine)
{
    printf ("%s", chaine);
}