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 un mail en attente de téléchargement
(ou de destruction).
Un fichier de configuration est utilisé pour se connecter à la
boite aux lettres.
Le mail à afficher est repéré par son numéro d'ordre dans la
liste des mails sur le serveur.
*/
#define appli // pour la déclaration de variables globales à l'application
/* variable globale au source
(pour éviter des tonnes de passages de paramètres) */
int ctypeorig; // type principal du mail
int ctype; // type de la section courante
// 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 */
void main (int nbarg, char *varg[])
{
FILE *fconf; // descripteur du fichier de configuration
int numes; // numéro du mail courant
// récupération du nom de l'exécutable
memcom (*varg);
// si commande lancée avec une option
if (--nbarg > 1 && varg [1][0] == '-')
{
// prendre en compte les options -h, -H, -b et -B
switch (varg [1][1])
{
case 'h' : opthb = 1;
break;
case 'H' : opthb = 3;
break;
case 'b' : opthb = 5;
break;
case 'B' : opthb = 7;
break;
// cas d'une option incorrecte
default : psyntaxe ("SYNT_VOIRMAIL");
// on n'ira pas plus loin
return;
}
// un argument traité
nbarg --;
varg ++;
}
else
// sinon pas d'option
opthb = 0;
// controle du nombre d'arguments
if (nbarg == 2)
{
// 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 numéro de mail
numes = atoi (varg [1]);
// afficher ce mail si possible
if (numes > 0 && numes <= nbmails ())
{
// entête
affiche_entete (numes);
// et contenu
affiche_corpsmail ();
}
else if (numes > 0)
// "Numéro de mail trop grand"
affiche_err ("NUMAIL_TROP_GRAND");
else
// "Numéro de mail %s incorrect"
aff_err_arg ("NUMAIL_FAUX", varg [1]);
// se déconnecter proprement du serveur pop
deconnect_pop ();
}
// on n'a plus besoin du fichier de configuration
fclose (fconf);
}
}
// sinon
else
// "Syntaxe : %s [-(h|H|b|B)] numéro_message fichier_configuration"
psyntaxe ("SYNT_VOIRMAIL");
// pour faire plaisir à gcc qui veut une fonction main de type int
return;
}
/* lit l'entête du message choisi et l'affiche */
void affiche_entete (int numes)
{
char bufw [120]; // buffer d'envoi d'une requête
// buffers pour affichage ordonné des caractéristiques du message
char bufFrom [120], bufXorig [120], bufTo [120], bufCc [120],
bufReply [120], bufSubject [120];
int analsuiv; // indicateur : il faudra traiter la ligne suivante
char *varenv_xorig; // variable d'environnement libremail_xorig
char xorig; // information utile de libremail_xorig
// 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)
{
puts (buf_lect);
return;
}
// lecture et mémorisation des caractéristiques du message
do
{
// récupération si nécessaire du charset ou de la
// bordure dans la 2ème ligne du champ Content-Type
if (analsuiv)
{
// si mode multipart
if (ctypeorig & Multipart)
{
// si on trouve une bordure, la mémoriser
if (mem_boundary ())
// dans ce cas, l'analyse ne se poursuivra
// pas sur les lignes suivantes
analsuiv = 0;
}
// sinon
else
{
// mémoriser le jeu de caractères
lire_charset ();
// l'analyse ne se poursuivra pas sur les lignes suivantes
analsuiv = 0;
}
}
// mémorisation des caractéristiques importantes
if (start ("Date"))
puts (buf_lect); // la date est affichée directement
else if (start ("From"))
memconvbuf (bufFrom);
else if (start ("X-Original-From") && xorig != 'n')
memconvbuf (bufXorig);
else if (start ("To"))
memconvbuf (bufTo);
else if (start ("Cc"))
memconvbuf (bufCc);
else if (start ("Reply-To"))
memconvbuf (bufReply);
else if (start ("Subject"))
memconvbuf (bufSubject);
else if (start ("Content-Type"))
{
// récupérer la valeur du champ Content-Type
ctypeorig = recup_ctype ();
// si ce type correspond au texte du mail
if (ctypeorig == TextPlain || ctypeorig == TextHtml)
{
// mémoriser le jeu de caractères
if (! lire_charset ())
// à partir de cette ligne ou de la suivante
analsuiv = 1;
}
// sinon si mode multipart
else if (ctypeorig & Multipart)
{
// mémoriser la bordure
if (! mem_boundary ())
// à partir de cette ligne ou de la suivante
analsuiv = 1;
}
}
else if (start ("Content-Transfer-Encoding"))
mem_encodage ();
// lire la ligne suivante de l'entête du message
lire_pop ();
}
while (buf_lect [0] != '\0'); // lecture entête terminée si ligne vide
// affichage de certaines caractéristiques mémorisées
if (bufFrom [0] && (! bufXorig [0] || xorig == '2'))
puts (bufFrom);
if (bufXorig [0])
puts (bufXorig);
if (bufTo [0])
puts (bufTo);
if (bufCc [0])
puts (bufCc);
if (bufReply [0])
puts (bufReply);
if (bufSubject [0])
puts (bufSubject);
}
/* lit le contenu du message choisi et l'affiche */
void affiche_corpsmail ()
{
// sauter la ligne blanche qui précède le message
lire_pop ();
// 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;
}
}
// 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) && ! fin_mail ());
// 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 (fin_mail ())
{
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
// on s'arrête en fin de mail, ou sur la prochaine bordure
while (! fin_mail () && (nbordures == 0 || ! surbordure ()))
{
// 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
lire_pop ();
// si mode multipart/report, on saute les entêtes de section
if (multiprep && nbordures && surbordure ())
{
do
lire_pop ();
while (*buf_lect && ! fin_mail ());
}
}
// 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 (ou text/html) */
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
lire_pop ();
}
// on s'arrête en fin de mail
while (! fin_mail ());
}
/* Ce qui suit est une adaptation des fonctions de trtsection
en remplaçant la fonction lire_fmail par lire_pop */
/* avancer jusqu'à la section suivante si
on n'est pas sur un marqueur de section */
void prochaine_section ()
{
// tant qu'on n'est pas sur une bordure
while (! surbordure ())
{
// avancer d'une ligne
lire_pop ();
// si problème de structure du mail (fin de mail rencontrée)
if (fin_mail ())
return; // sortir
}
// si bordure trouvée, lire la ligne suivante
if (buf_lect [0] == '-')
lire_pop ();
}
/* mémorise le type, le jeu de caractères et le mode d'encodage de la section */
void recup_infos_section ()
{
// initialisation : type de section non trouvé
ctype = 0;
// tant qu'on est dans l'entête de la section, on va chercher
// des informations dans toutes les lignes sachant qu'elles
// peuvent apparaitre dans un ordre quelconque
while (buf_lect [0])
{
// type de la section
if (start ("Content-Type"))
ctype = recup_ctype ();
// mode d'encodage des caractères
else if (start ("Content-Transfer-Encoding"))
mem_encodage ();
// si section multipart
if (ctype & Multipart)
// mémoriser la bordure quand on la trouve
mem_boundary ();
// sinon
else
// récupérer le jeu de caractères utilisé quand on le trouve
lire_charset ();
// passer à la ligne suivante
lire_pop ();
}
}
// se positionner sur la section texte du mail (si l'on n'y est pas)
// se positionner (si l'on n'y est pas) sur la section text/plain
// ou text/html du mail, en fonction du paramètre typetexte
void posit_section (int typetexte)
{
// tant qu'on n'a pas trouvé la section contenant
// le texte du mail et non fin de mail
while (ctype != typetexte && buf_lect [0] != '\0')
{
// si une bordure a été mémorisée
if (nbordures)
// se positionner sur la section suivante
prochaine_section ();
// récupérer les informations sur la section
recup_infos_section ();
}
// message d'erreur si on est arrivé en fin de mail
if (fin_mail ())
{
// Problème de structure d'un mail multi section : fin de mail atteinte
sprintf (buf_lect, " %s\n", message ("PB_STRUCT_MAIL"));
}
}
// lister les pièces jointes
void liste_pj ()
{
int posjoint; // position du nom du fichier joint
char nomjoint [120]; // nom du fichier joint
int nbext; // nombre d'extentions du fichier
int derctype; // pour mémoriser champ content-type de la section
int i; // compteur
// on ne conserve que la bordure de premier niveau
// (permet de sauter le texte HTML en mode multipart/alternative)
nbordures = 1;
// tant que non fin de mail et pas sorti de la section de premier niveau
while (nbordures && ! fin_mail ())
{
// se positionner sur la prochaine section si on n'y est pas déjà
prochaine_section ();
// terminé s'il n'y en a plus
if (fin_mail ())
return;
// réinitialisation type de section
derctype = 0;
// chercher et mémoriser le nom du fichier joint s'il y en a un
do
{
// mémoriser les sections message/rfc822 et text/html
if (start ("Content-Type"))
derctype = recup_ctype ();
// chercher si la ligne contient un nom de fichier joint
majligne ();
posjoint = posnomfic ();
// si trouvé hors d'une section text/html
if (posjoint && derctype != TextHtml)
{
// récupérer son nom
// "-> Fichier joint : "
strcpy (nomjoint, message ("FICJOINT"));
i = strlen (nomjoint);
nbext = 0;
// convertir les données encodées comme dans une entête
majlignentete ();
// recopie du nom de fichier sans déborder du tableau
while (buf_lect [posjoint] != '"' && buf_lect [posjoint])
{
// sans les (horribles) blancs qu'il pourrait contenir !!!
// et sans déborder du tableau
if (buf_lect [posjoint] != ' ' && i < sizeof (nomjoint))
nomjoint [i++] = buf_lect [posjoint];
// passer au caractère suivant
posjoint++;
// on compte les . (nombre d'extentions) du fichier
// à partir du 2ème caractère du nom
if (buf_lect [posjoint] == '.')
nbext ++;
}
// terminer la chaine générée
if (i + 1 >= sizeof (nomjoint))
i = sizeof(nomjoint) - 1;
nomjoint [i] = '\0';
}
// passer à la ligne suivante
lire_pop ();
}
while (! posjoint && buf_lect [0] != '\0' && ! fin_mail ());
// si fichier joint trouvé hors d'une section text/html
if (posjoint && derctype != TextHtml)
{
// actuellement tous les fichiers joints avec extention peuvent
// contenir des virus, on accepte quand même les .exe
if (nbext > 1 || (nbext == 1 && strcmp (nomjoint + i - 4, ".exe\n")
!= 0 && strcmp (nomjoint + i - 4, ".EXE\n") != 0))
{
// se positionner sur la première ligne du contenu du fichier
while (buf_lect [0] != '\0' && ! fin_mail ())
lire_pop ();
if (! fin_mail ())
lire_pop ();
// si le fichier commence par les caractères MZ
// (on teste l'encodage base64 correspondant)
if (buf_lect [0] == 'T' && buf_lect [1] == 'V'
&& buf_lect [2] >= 'o' && buf_lect [2] <= 'r')
// il peut s'agir d'un virus MS-DOS / Windows
// " *** VIRUS ? ***\n"
strcpy (nomjoint + i, message ("VIRUS_POSSIBLE"));
}
// afficher le nom du fichier joint trouvé
puts (nomjoint);
}
// sinon, si section message/rfc822 trouvée
else if (derctype == Mesrfc822)
// la récupérer et la traiter
recup_rfc822 ();
}
}
/* récupère le contenu d'une section rfc822 */
void recup_rfc822 ()
{
char fichtmp [18]; // fichier pour mémoriser le contenu de la section
FILE *ftmp; // descripteur associé à ce fichier
char commande [28]; // commande à exécuter pour afficher cette section
// fabriquer un nom de fichier de travail
sprintf (fichtmp, "/tmp/mail-%d", getpid ());
// l'ouvrir en écriture
ftmp = fopen (fichtmp, "w");
// terminé si problème d'accès au fichier
if (! ftmp)
{
// "Impossible de récupérer un mail en pièce jointe"
affiche_err ("IMPOS_RECUP-MAILJOINT");
return;
}
// afficher une ligne de séparation
putchar ('\n');
// lecture de la première ligne non vide de la section
lire_pop ();
// tant que non fin de section
while (! surbordure () && ! fin_mail ())
{
// mémoriser la ligne
fputs (buf_lect, ftmp);
fputc ('\n', ftmp);
// et lire la suivante
lire_pop ();
}
// la section a été entièrement récupérée
fclose (ftmp);
// afficher cette section
sprintf (commande, "voirfmail %s", fichtmp);
system (commande);
// on peut détruire le fichier de travail
unlink (fichtmp);
}