/*
    Fichier voirfmail.c
    Auteur Bernard Chardonneau

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

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


    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 <stdio.h>
#include <string.h>
#include "messages.h"
#include "buflect.h"
#include "fmail.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_mail ();
void aff_texte ();
void genligne (char *chaine);


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


int opth;  // option affichage de la section text/html au lieu de text/plain


/* programme principal */

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

    // si commande lancée avec l'option -h ou -H
    if (--nbarg > 1 && varg [1][0] == '-' && (varg [1][1] | 0x20) == 'h')
    {
        // mémoriser cette option
        if (varg [1][1] == 'h')
            opth = 1;
        else
            opth = 2;

        // un argument traité
        nbarg --;
        varg ++;
    }
    else
        // sinon pas d'option -h ni -H
        opth = 0;

    // 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 puis son contenu
            aff_entete ();

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

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


/* lit le message choisi et l'affiche
   cette fonction traite essentiellement l'entête du mail
   puis appelle aff_mail pour l'affichage du corps du mail */


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, posTo, posCc, posReply, posSubject, posContent;


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

    // 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"))   // pour le fun
            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 ("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

    // affichage ordonné des champs principaux de l'entête
    if (posDate >= 0)
        affchamp (posDate, 0);
    if (posFrom >= 0)
        affchamp (posFrom, 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);

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

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

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


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


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

void aff_mail ()
{
    // si mode multipart/mixed ou multipart/related, mémoriser
    // le type et la bordure éventuelle de la section suivante
    if ((ctypeorig == MultipMixed) || (ctypeorig == MultipRel))
        mem_soustype ();

    // se positionner sur la section texte (ou text/html si option -h)
    // du mail (si l'on n'y est pas)
    if (opth)
        posit_texthtm ();
    else
        posit_texte ();

    // message d'avertissement éventuel
    test_encode ();

    // 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 (opth)
            // "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");
    }

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

        // si traitement des balises html
        if (opth == 2)
        {
            // supprimer les balises html
            sup_balhtm ();

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

        // et affichage de la dernière ligne lue
        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 (ctypeorig == 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 affichage d'un mail de type text/plain */

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

    // message d'avertissement éventuel
    test_encode ();

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

        // si traitement des balises html
        if (opth == 2)
        {
            // supprimer les balises html
            sup_balhtm ();

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

        // et affichage de la dernière ligne lue
        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);
}