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.
On peut utiliser les flèches et les autres touches de déplacement
pour parcourir le contenu du mail si celui ci tient sur plus d'une
page.
Cet outil peut être lancé automatiquement par l'outil vmailsj
(lui même lancé par vmaildir) lorsqu'on sélectionne un répertoire
de l'arborescence des mails, puis un mail particulier.
*/
#define appli // pour la déclaration de variables globales à l'application
/* variable globale au source
(pour éviter des tonnes de passages de paramètres) */
char **ligne; // les lignes de texte du mail
int maxlig; // nombre maximum de lignes mémorisées
int colonsaut; // nombre de colonnes avant un passage à la ligne souhaitable
int opthb = 0; // options d'affichage relatives aux balises HTML
int lig_nonvide; // mémorise s'il y a des 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);
// 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)
{
// fixer la taille initiale de la liste des fichiers mail
maxlig = maxligini;
// allouer la liste des fichiers mail
ligne = malloc (maxlig * sizeof (char *));
// vérification allocation
if (! ligne)
// "Manque de place mémoire, le logiciel %s ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", nomcom ());
// mémoriser l'entête du mail
mem_entete ();
// puis son contenu
mem_corpsmail (TextPlain);
// fermer ce fichier
fclose (fmail);
// afficher le mail
navigation (varg [1]);
}
else
// "Fichier %s non trouvé"
aff_err_arg ("FICH_ABSENT", varg [1]);
}
else
// "Syntaxe : %s nom_fichier_mail"
psyntaxe ("SYNT_GENE_FICMAIL");
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* lit le message choisi et mémorise les champs importants de son entête */
void mem_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
// 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';
// déterminer la largeur d'affichage
lig_col ();
// et la largeur après laquelle un passage à la ligne est souhaitable
if (colonpage < defaut_colon)
colonsaut = colonpage;
else
colonsaut = defaut_colon;
// 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
genligne (buf_lect); // le mailer est mémorisé 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
// affichage ordonné des champs principaux de l'entête
if (posDate >= 0)
memchamp (posDate, 0);
if (posFrom >= 0 && (posXorig < 0 || xorig == '2'))
memchamp (posFrom, 1);
if (posXorig >= 0)
memchamp (posXorig, 1);
if (posTo >= 0)
memchamp (posTo, 1);
if (posCc >= 0)
memchamp (posCc, 1);
if (posReply >= 0)
memchamp (posReply, 1);
if (posSubject >= 0)
memchamp (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);
}
/* mémorise un champ de l'entête d'une ou plusieurs lignes
repéré à partir de sa position dans le fichier mail */
void memchamp (long pos_deblig, int conversion)
{
// se positionner sur la ligne contenant le champ
fseek (fmail, pos_deblig, SEEK_SET);
// lire cette ligne
lire_fmail ();
// interpréter si nécessaire les caractères spéciaux
if (conversion)
majlignentete ();
// forcer le premier caractère de la ligne en majuscules
// bien qu'il doit l'être déjà
*buf_lect = *buf_lect & 0x5F;
// et afficher la ligne
genligne (buf_lect);
// lire la ligne suivante
lire_fmail ();
// tant qu'elle fait partie du même champ
while (*buf_lect == ' ' || *buf_lect == '\t')
{
// interpréter si nécessaire les caractères spéciaux
if (conversion)
majlignentete ();
// et afficher la ligne
genligne (buf_lect);
// lire la ligne suivante
lire_fmail ();
}
}
/* lit le corps du mail et mémorise son contenu
dans un mail multi section, c'est la section du type passée
en paramètre (text/plain si appel depuis le programme
principal) qui est affichée */
void mem_corpsmail (int typesection)
{
// sauter la ligne blanche entre l'entête et le corps du mail
lire_fmail ();
// mémorisation du contenu du mail
if (ctypeorig & Multipart)
// il faudra analyser les sections
memo_mail (typesection);
else
// une simple mémorisation du texte suffit
memo_texte ();
// si aucune ligne utile mémorisée
if (nb_lignes < 2)
// "Aucun texte récupéré : ce n'est pas un fichier mail"
genligne (message ("NON_FICMAIL"));
}
/* 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
genligne (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
genligne ("");
// et mémoriser le fait qu'elle est vide
lig_nonvide = 0;
}
}
/* mémorisation du contenu d'un mail en mode multipart */
// 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 ou text/html du mail
if (multipalter)
posit_section (typetexte);
// générer une ligne de séparation avec l'entête
genligne ("");
// si structure du mail non conforme, message d'erreur
if (! lire_fmail ())
{
if (typetexte == TextPlain)
// "Pas de zone texte dans ce mail !!!"
genligne (message ("MANQUE_ZONE_TEXTE"));
else
// "Pas de zone texte html dans ce mail !!!"
genligne (message ("MANQUE_ZONE_HTML"));
}
// si on doit supprimer la partie html avant <body
if (opthb & 4)
// le mémoriser
avantbody = 1;
else
avantbody = 0;
// lecture et mémorisation 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
else
{
// on pourra éventuellement regrouper des lignes
if (buf_lect [strlen (buf_lect)-1] == '\n')
genligne (buf_lect);
else
regroupeligne (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, si trop de lignes
// ont été mémorisées ou sur la prochaine bordure
while (nb_lignes < maxlig && (nbordures == 0 || ! surbordure ()));
// si mode multipart mixed on va lister les pièces jointes
if (multipmixed)
liste_pj ();
}
/* lecture et mémorisation d'un mail de type text/plain */
void memo_texte ()
{
// si texte encodé base 64
if (encodage_texte == Base64)
// générer une ligne de séparation avec l'entête
genligne ("");
// si on doit supprimer la partie html avant <body
if (opthb & 4)
// le mémoriser
avantbody = 1;
else
avantbody = 0;
// 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
else
{
// on pourra éventuellement regrouper des lignes
if (buf_lect [strlen (buf_lect)-1] == '\n')
genligne (buf_lect);
else
regroupeligne (buf_lect);
}
// et lecture de la suivante
}
// on s'arrête en fin de fichier ou si trop de lignes ont été mémorisées
while (lire_fmail () && nb_lignes < maxlig);
}
/* mémorise une ligne du mail */
void genligne (char *buffer)
{
char * nouvligne; // tableau alloué dynamiquement pour mémoriser la ligne
static char pb_alloc [50]; // message d'erreur si allocation impossible
int taille_ligne; // longueur de la ligne mémorisée
int taille_utile; // longueur de la ligne sans le \n éventuel
int i; // compteur
// récupérer la longueur de la ligne
taille_ligne = strlen (buffer);
// si ligne longue
if (taille_ligne > colonsaut)
{
// on tente de la tronquer à moins de 'colonsaut' car
i = colonsaut;
// chercher un blanc pour passer à la ligne
while (i > 0 && buffer [i] != ' ')
i--;
// si pas de blanc trouvé
if (i == 0)
{
// on en cherche un dans l'autre sens
i = colonsaut;
while (i < taille_ligne && i < colonpage && buffer [i] != ' ')
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;
// ne pas compter le passage à la ligne en fin de buffer
if (taille_ligne && buffer [taille_ligne - 1] == '\n')
taille_utile = taille_ligne - 1;
else
taille_utile = taille_ligne;
// allouer un tableau pour mémoriser la ligne
nouvligne = (char *) malloc (taille_utile + 1);
// si le tableau a pu être alloué et on peut mémoriser cette ligne de texte
if (nouvligne && ajoutlignepossible ())
{
// recopier les données dans ce tableau
for (i = 0; i < taille_utile; i++)
nouvligne [i] = buffer [i];
// terminer la chaine
nouvligne [taille_utile] = '\0';
// rajouter la ligne mémorisée dans le texte
ligne [nb_lignes++] = nouvligne;
// si la ligne a été tronquée, traiter la suite
if (taille_ligne < strlen (buffer) && nb_lignes < maxlig)
genligne (buffer + taille_ligne + 1);
}
else
{
// sinon avertir d'un manque de mémoire
// "** MANQUE D'ESPACE MEMOIRE ==> TEXTE TRONQUE **"
strcpy (pb_alloc, message ("TEXTE_TRONQUE"));
ligne [nb_lignes++] = "";
ligne [nb_lignes++] = pb_alloc;
// et aller en fin de fichier pour arrêter sa lecture
fseek (fmail, 0, SEEK_END);
}
}
/* vérifie si l'on peut insérer un élément de plus dans le tableau
ligne, et redimensionne ce tableau si nécessaire */
int ajoutlignepossible ()
{
char **nouvtableau; // adresse du tableau de remplacement
int nouvtaille; // et sa taille
int element; // compteur : numéro d'élément dans les tableaux
// cas simple : il reste au moins une place de libre dans le tableau
if (nb_lignes + 1 < maxlig)
return (1);
// calculer la nouvelle taille du tableau
// l'augmentation est alternativement de 50 % ou 33 % de manière
// à ce que la taille double après 2 réallocations
if (maxlig % 3)
nouvtaille = maxlig + (maxlig / 2);
else
nouvtaille = maxlig + (maxlig / 3);
// vérification allocation
if (nouvtableau)
{
// copie du contenu de l'ancien tableau dans le nouveau
for (element = 0; element < maxlig; element ++)
nouvtableau [element] = ligne [element];
// destruction de l'ancien tableau
free (ligne);
// que l'on remplace par le nouveau
ligne = nouvtableau;
maxlig = nouvtaille;
}
// retourne le résultat de la possibilité d'insertion d'éléments
return (nb_lignes + 1 < maxlig);
}
/* recharge le mail en mémoire
Cette fonction prend en compte un changement de la
longueur maximale des lignes, ou du mode d'affichage */
void rechargemail (char *nomfic, int mode_affich)
{
// libérer la mémoire pour les lignes mémorisées
while (nb_lignes > 0)
free (ligne [--nb_lignes]);
// on va relire le fichier mail
fmail = fopen (nomfic, "r");
// mémoriser l'entête du mail
mem_entete ();
// avec le nouveau mode d'affichage
mem_corpsmail (mode_affich);
// lecture terminée
fclose (fmail);
// si numéro de ligne courant trop grand
if (lignecour >= nb_lignes)
// le corriger
lignecour = nb_lignes - 1;
// idem pour la position à l'écran
if (lignecran > nb_lignes)
lignecran = nb_lignes;
}
/* affiche la liste des mails du répertoire et permet de
la parcourir même si elle tient sur plusieurs pages */
void navigation (char *nomfic)
{
int car; // caractère tapé au clavier
int erreurs; // nombre frappes caractères inconnus comme commandes
char curdir [szchemin]; // répertoire courant
char nouvnom [szchemin + 12]; // pour rebaptiser le fichier après première
// visualisation ou le mettre à la poubelle
char ficimpr [20]; // fichier d'impression
char fic_mailtrad [20] = ""; // fichier contenant le mail traduit
FILE *tmpfic; // descripteur du fichier d'impression
char *editeur; // éditeur utilisé pour modifier les mails
int colonprec; // nombre de colonnes d'affichage avant un ^L
int i; // compteur de lignes (pour générer fichier d'impression)
int opthb_prec; // valeur précédente de opthb
int mode_affich; // mémorise le mode d'affichage de la section texte
int traduit; // mémorise si mail affiché dans langue origine ou traduit
// configurer la liaison clavier pour lecture directe avec timeout
mode_raw ();
case HOME :
case HOMEg : monte (lignecour);
erreurs = 0;
break;
case FIN :
case FINg : descend (nb_lignes - lignecour - 1);
erreurs = 0;
break;
case 0 : // aide si trop d'erreurs ou à la demande
case F1 : effpage ();
// "Touches utilisables :\n"
// "flèches Pageup, Pagedown, Home et Fin"
// "pour se déplacer d'une ou plusieurs lignes"
// "i pour Identifier le fichier mail"
// "r pour Répondre au mail, t pour le Transférer"
// "s pour le Supprimer, m pour Modifier avant envoi"
// "u pour restaurer un mail dans la poubelle"
// "j pour Joindre des fichiers à un mail à envoyer"
// "c pour Copier le mail ou l'adresse d'expéditeur"
// "/ ou ? pour rechercher une chaine dans le mail"
// "p pour l'imPrimer"
// "h pour afficher la section Html sans modification"
// "H pour afficher la section Html sans les balises Html"
// B pour afficher à partir de la balise <Body ...> sans les balises Html"
// "l pour spécifier une Langue, T pour Traduire le mail"
// "entrée pour récupérer les fichiers joints"
// "Control L pour réafficher la page"
affiche_msg ("AIDE_CHOIX_ADR-1");
affiche_msg ("AIDE_CHOIX_ADR-2");
affiche_msg ("AIDE_CHOIX_ADR-3");
affiche_msg ("AIDE_VMAILFIC_SJ1");
affiche_msg ("AIDE_VMAILFIC-1");
affiche_msg ("AIDE_VMAILFIC-2");
affiche_msg ("AIDE_VMAILFIC-3");
affiche_msg ("AIDE_VMAILFIC_SJ2");
affiche_msg ("AIDE_VMAILFIC-4");
affiche_msg ("AIDE_VMAILFIC-5");
affiche_msg ("AIDE_VMAILFIC-6");
affiche_msg ("AIDE_VMAILFIC-7");
affiche_msg ("AIDE_VMAILFIC-8");
affiche_msg ("AIDE_VMAILFIC-9");
affiche_msg ("AIDE_VMAILFIC-10");
affiche_msg ("AIDE_VMAILFIC-11");
affiche_msg ("AIDE_VMAILFIC-12");
affiche_msg ("AIDE_CHOIX_ADR-7");
// variante pour la touche Esc
if (util_systemd ())
// "q ou Esc (2 fois) pour Quitter ce programme"
affiche_msg ("AIDE_VMAIL2");
else
// "q ou Esc pour Quitter ce programme"
affiche_msg ("AIDE_VMAIL");
// "Appuyer sur une touche pour continuer"
affiche_msg ("ATTENTE_CLAVIER");
leccar ();
affpage ();
erreurs = 0;
break;
// réaffiche la page en tenant compte d'un
// éventuel redimentionnement de la fenêtre
// mémoriser la lageur précédente de la page
case CTRL : colonprec = colonpage;
// déterminer la nouvelle largeur d'affichage
lig_col ();
// si elle a changé
if (colonpage != colonprec)
{
// recalculer la largeur après laquelle un
// passage à la ligne est souhaitable
if (colonpage < defaut_colon)
colonsaut = colonpage;
else
colonsaut = defaut_colon;
// recharger le mail
rechargemail (nomfic, mode_affich);
}
// réafficher la page
affpage ();
erreurs = 0;
break;
// identifie le fichier mail (donne son nom)
case 'i' : effpage ();
// "\nFichier : %s/%s\n\n"
// "Appuyer sur une touche pour continuer"
printf (message ("AFF_CHEMFICH"), curdir, nomfic);
affiche_msg_nocr ("ATTENTE_CLAVIER");
leccar ();
affpage ();
erreurs = 0;
break;
// réponse à un mail
case 'r' : execom ("repmail", nomfic);
// on revient à la liste des mails
car = ESC;
break;
// transfert d'un mail
case 't' : execom ("trsfmail", nomfic);
// on revient à la liste des mails
car = ESC;
break;
// impression du mail
case 'p' : // on crée un fichier tampon dans le répertoire
// /tmp pour éviter les problèmes lorsque le
// répertoire courant est protégé en écriture
sprintf (ficimpr, "/tmp/impr-mail-%04X", getpid ());
// ouvrir en écriture un fichier tampon
tmpfic = fopen (ficimpr, "w");
// remplir de fichier d'impression
for (i = 0; i < nb_lignes; i++)
fprintf (tmpfic, "%s\n", ligne [i]);
fclose (tmpfic);
// imprimer le fichier généré
execom ("lp", ficimpr);
// et le supprimer
unlink (ficimpr);
// l'appel d'execom suppose de réafficher la page
// Note : ça crée un léger clignottement qui permet
// de visualiser la prise en compte de l'impression
affpage ();
erreurs = 0;
break;
// affichage de la section text/html si elle existe
case 'h' :
case 'H' :
case 'b' :
case 'B' : effpage (); // on efface la page
// si mail multisection ou mail en HTML pur
if (ctypeorig != TextPlain)
{
// récupérer la valeur précédente de opthb
opthb_prec = opthb;
// prendre en compte la demande de changement
switch (car)
{
case 'h' : opthb = 1;
break;
case 'H' : opthb = 3;
break;
case 'b' : opthb = 5;
break;
case 'B' : opthb = 7;
break;
}
// si on n'a pas changé d'option d'affichage
if (opthb == opthb_prec)
{
// revenir à un affichage en mode texte
opthb = 0;
// "Retour de l'affichage en mode texte"
affiche_msg_nocr ("AFFICH_TEXTE");
attendre (1);
// on affichera la section text/plain
mode_affich = TextPlain;
}
// sinon
else
// on affichera la section text/html
mode_affich = TextHtml;
// recharger le mail
rechargemail (nomfic, mode_affich);
}
// sinon message d'erreur
else
{
// "Ce mail ne contient qu'une section, commande sans effet"
affiche_msg_nocr ("MAIL_MONOSECTION");
attendre (2);
}
// réafficher la page
affpage ();
erreurs = 0;
break;
// choix d'une langue pour traduction
case 'l' : effpage ();
fflush (stdout);
// un fichier de traduction a des chances d'exister
if (*fic_mailtrad)
// le détruire s'il existe (traduction à refaire)
unlink (fic_mailtrad);
// selectionner la langue à traduire
choixlangue (1);
// réafficher la page
affpage ();
erreurs = 0;
break;
// traduction du mail
case 'T' : // si on affichait la version traduite du mail
if (traduit)
{
// recharger le mail d'origine
rechargemail (nomfic, mode_affich);
traduit = 0;
}
// sinon faire la traduction et la mémoriser
else
traduit = trad_mail (nomfic, mode_affich,
fic_mailtrad, ligne);
// réafficher la page
affpage ();
erreurs = 0;
break;
case SUPR : // suppression d'un mail
case 's' : // récupérer le répertoire des mails supprimés
if (getenv ("mailpoub"))
strcpy (nouvnom, getenv ("mailpoub"));
else
*nouvnom = '\0';
// si on est dans ce répertoire
if (strcmp (curdir, nouvnom) == 0)
{
// supprimer le fichier mail
unlink (nomfic);
// on revient à la liste des mails
car = ESC;
}
// sinon (cas général)
else if (*nouvnom)
{
// créer le répertoire poubelle si nécessaire
mkdir (nouvnom, 0755);
// et y mettre le fichier mail
strcat (nouvnom, "/");
strcat (nouvnom, nomfic);
// sans l'extention des fichiers à lire
if (nouvnom [strlen (nouvnom) - 2] == '.')
nouvnom [strlen (nouvnom) - 2] = '\0';
rename (nomfic, nouvnom);
// on revient à la liste des mails
car = ESC;
}
// sinon (racine des mails inconnue)
else
{
effpage ();
// "Racine des mails inconnue, pas de suppression"
affiche_msg_nocr ("REP_RACINE_INCONNU");
attendre (2);
affpage ();
}
erreurs = 0;
break;
// restauration d'un mail
case 'u' : // si on est dans le répertoire poubelle
if (strcmp (curdir, getenv ("mailpoub")) == 0)
{
// déplacer le fichier mail dans entree
sprintf (nouvnom, "../%s/%s",
ficdir ("DIR_ENTREE"), nomfic);
rename (nomfic, nouvnom);
// on revient à la liste des mails
car = ESC;
}
// sinon, message d'erreur
else
{
effpage ();
// "Seuls les mails dans la poubelle peuvent être restaurés"
affiche_msg_nocr ("MAIL_NON_RESTAUR");
attendre (2);
}
affpage ();
erreurs = 0;
break;
// modification d'un mail à envoyer
// ou rajout de pièces jointes au mail
case 'm' :
case 'j' : effpage ();
fflush (stdout);
// si on est dans le répertoire des mails à envoyer
if (getenv ("mailenv") &&
strcmp (curdir, getenv ("mailenv")) == 0)
{
// traitement en fonction de la touche tapée
if (car == 'm')
{
// modifier le mail
editeur = getenv ("EDITOR");
if (editeur)
execom (editeur, nomfic);
else
execom ("vi", nomfic);
}
else
// joindre des fichiers
execom ("joindre", nomfic);
// on revient à la liste des mails
car = ESC;
}
else
{
// sinon, message d'erreur
// "Seuls les mails en attente d'envoi peuvent être modifiés"
affiche_msg_nocr ("MAIL_NON_MODIF");
attendre (2);
affpage ();
}
erreurs = 0;
break;
// copie de tout ou partie du mail
case 'c' : effpage ();
fflush (stdout);
cop_mail ();
erreurs = 0;
affpage ();
break;
// "Vous n'êtes pas positionné sur une pièce jointe"
affiche_msg_nocr ("NON_POS_PJ");
attendre (2);
}
affpage ();
erreurs = 0;
break;
case '/' : // recherche d'une chaine de caractères
case '?' : recherche (car);
erreurs = 0;
case 'q' : // sortie du programme
case ESC : break;
// sortie aussi sur :q
case ':' : car = leccar ();
if (car == 'q')
{
car = ESC;
break;
}
default : putchar (7); // bip
// si trop d'erreurs, afficher l'aide
if (++erreurs == 5)
ungetc (0, stdin); // on ira sur l'aide
}
}
while (car != 'q' && car != ESC);
// si le fichier n'avait pas encore été visualisé
if (nomfic[strlen (nomfic) - 2] == '.')
{
// on enlèvera le .n de l'ancien nom
strcpy (nouvnom, nomfic);
nouvnom [strlen (nouvnom) - 2] = '\0';
// et voila !
rename (nomfic, nouvnom);
}
// si on a appelé ce programme directement
if (! getenv ("mailenv"))
{
// descendre en bas de page
while (lignecran++ < lignepage && lignecour++ < nb_lignes)
putchar ('\n');
// retour à la configuration standard du clavier
mode_normal ();
}
// si un fichier de traduction du mail a été créé (ou si son nom existe)
if (*fic_mailtrad)
// détruire le fichier s'il est présent
unlink (fic_mailtrad);
}
/* affiche une ligne du mail */
void affligne (int numlig)
{
char *maligne; // pour éviter de trop manipuler des indices de tableau
int i; // simple compteur
// initialisation
i = 0;
maligne = ligne [numlig];
// copie de la ligne sans déborder
while (*maligne && i < colonpage)
{
// cas général, on recopie le caractère courant
if (*maligne != '\t')
putchar (*maligne);
// si tabulation
else
// écrire des blancs
do
{
putchar (' ');
i++;
}
// sans déborder de la fenêtre d'affichage
while (i % 8 && i < colonpage);
// passer au caractère suivant
maligne ++;
}
}
/* copie de tout ou partie du fichier mail */
void cop_mail ()
{
char nomfic [szchemin]; // nom du fichier résultat
FILE *fcopy; // descripteur fichier utilisé pour une copie
int choix; // choix de la zone à copier
int ligFrom, ligXorig; // lignes du champ expéditeur
int i; // compteur (pour copier le mail dans un fichier)
// choix de la zone à copier
// "1) copie du mail complet"
// "2) copie du message seul"
// "3) copie de l'adresse de l'expéditeur"
// "4) rajout de l'expéditeur dans le carnet d'adresse"
// "5) rajout de l'expéditeur dans les adresses refusées"
// "6) rajout du nom de domaine de l'expéditeur dans les adresses refusées"
affiche_msg ("MENU_COPIE-1");
affiche_msg ("MENU_COPIE-2");
affiche_msg ("MENU_COPIE-3");
affiche_msg ("MENU_COPIE-4");
affiche_msg ("MENU_COPIE-5");
affiche_msg ("MENU_COPIE-6");
// si rajout dans le carnet d'adresse ou la liste des expéditeurs refusés
if (choix >= 4 && getenv ("mailenv"))
{
// rechercher le répertoire racine de la messagerie
strcpy (nomfic, getenv ("mailenv"));
// à partir de la variable $mailenv on remonte au dernier /
i = strlen (nomfic);
while (nomfic [--i] != '/' && i)
; // ne rien faire, tout est dans la condition
if (choix == 4)
// rajout dans le carnet d'adresse
strcpy (nomfic + i + 1, ficdir ("FIC_CARNET-ADR"));
else
// rajout dans la liste des expéditeurs refusés
strcpy (nomfic + i + 1, ficdir ("FIC_REFUS_ADR"));
// l'ouvrir en écriture en fin de fichier
fcopy = fopen (nomfic, "a");
}
// sinon : copie dans un nouveau fichier
else
{
// afficher le répertoire courant
getcwd (nomfic, szchemin);
// "Répertoire courant : %s\n"
printf (message ("REPERT_COURANT"), nomfic);
// choix du fichier par l'opérateur
// "Chemin d'accès au fichier qui contiendra la copie ? "
affiche_msg_nocr ("CHEM_FIC_COPIE");
mode_normal ();
fgets (nomfic, sizeof (nomfic), stdin);
// création du fichier destinataire de la copie
fcopy = fopen (nomfic, "w");
}
// si ouverture du fichier réussie
if (fcopy)
{
// on se positionne en début de mail
i = 0;
// si copie du message (avec ou sans entête)
if (choix < 3)
{
// saut de l'entête ?
if (choix == 2)
{
while (*ligne [i])
i++;
i++;
}
// copie du mail complet ou du message
while (i < nb_lignes)
{
fputs (ligne [i++], fcopy);
fputc ('\n', fcopy);
}
}
// copie de l'adresse de l'expéditeur
else
{
// initialisation
ligFrom = 0;
ligXorig = 0;
// recherche de la ligne contenant l'adresse
do
{
strcpy (buf_lect, ligne [i]);
if (start ("From"))
ligFrom = i;
else if (start ("X-Original-From"))
ligXorig = i;
i++;
}
while (!start ("To") && *buf_lect);
// si expéditeur trouvé
if (ligXorig || ligFrom)
{
// choisir le meilleur entre From: et X-Original-From:
if (ligXorig)
{
strcpy (buf_lect, ligne [ligXorig]);
i = 17;
}
else
{
strcpy (buf_lect, ligne [ligFrom]);
i = 6;
}
// si ajout dans la liste des adresses refusées
if (choix > 4)
{
// rechercher l'adresse dans le champ expéditeur
while (buf_lect [i] != '@' && buf_lect [i])
i++;
// si refus de l'adresse (et pas du nom de domaine complet)
if (choix == 5)
{
// se positionner en début d'adresse
while (buf_lect [i] != '<' && buf_lect [i] != ' ')
i--;
i++;
}
}
// copier l'adresse dans le fichier
do
{
// pour la lisibilité du carnet d'adresse
if (buf_lect [i] == '<')
buf_lect [i] = ' ';
// copie d'un caractère et passage au suivant
fputc (buf_lect [i++], fcopy);
}
while (buf_lect [i] != '>' && buf_lect [i]);
// terminer la ligne
fputc ('\n', fcopy);
}
else
{
// sinon message d'erreur
// "Expéditeur non trouvé"
affiche_msg_nocr ("EXPED_ABSENT");
attendre (2);
}
}
// terminé, on ferme le fichier
fclose (fcopy);
}
else
{
// sinon, message d'erreur
// "Impossible de créer le fichier %s\n"
printf (message ("IMPOS_CRE_FICH"), nomfic);
montecurs ();
attendre (2);
}
// reconfigurer la liaison clavier pour lecture directe avec timeout
mode_raw ();
}
/* recherche d'une chaine de caractères dans le mail */
void recherche (int sens)
{
// chaine à rechercher, on utilise une variable statique
// pour garder sa valeur aux appels suivants de la fonction
static char chaine [120];
int car; // caractère lu au clavier
int limite; // ligne marquant une extrémité du mail
int trouve; // indicateur : ligne contenant la chaine trouvée
int i, j; // compteurs
// descendre en bas de page et effacer la dernière ligne
baspage ();
effligne ();
// saisir la chaine à rechercher
putchar (sens);
car = leccar ();
// si chaine vide, on conserve la précédente
if (car != '\n')
{
// sinon on mémorise la nouvelle chaine
i = 0;
do
{
// cas particulier : caractère d'effacement
if (car == RECULE || car == EFFCAR)
{
if (i > 0)
{
putchar (CTRH);
putchar (' ');
putchar (CTRH);
i--;
}
}
// cas général : affichage et mémorisation d'un caractère
else if (i < sizeof (chaine))
{
putchar (car);
chaine [i++] = car;
}
// lire le caractère suivant
car = leccar ();
}
// jusqu'à ce que chaine entièrement saisie
while (car != '\n');
// terminer la chaine
chaine [i] = '\0';
}
// initialisation variables pour recherche
if (sens == '/')
{
sens = 1;
limite = nb_lignes - 1;
}
else
{
sens = -1;
limite = 0;
}
// début de la recherche à partir d'une ligne voisine de la ligne courante
i = lignecour;
// répeter
do
{
// si on n'a pas atteint l'extrémité du mail
if (i != limite)
// descendre ou remonter d'une ligne selon le sens de recherche
i = i + sens;
else
// sinon aller à l'autre extrémité du mail
i = nb_lignes - 1 - limite;
// chercher si la chaine est présente dans la nouvelle ligne
trouve = dansligne (chaine, i);
}
// jusque chaine de caractères trouvée ou tout le mail exploré
while (! dansligne (chaine, i) && i != lignecour);
// si chaine non trouvée
if (! trouve)
{
// afficher un message d'erreur
// " Chaine non trouvée"
affiche_msg_nocr ("CHAINE_ABSENTE");
putchar (7);
}
// revenir en début de ligne
putchar ('\r');
// remonter à la ligne sur laquelle on était
j = lignepage;
while (j-- > lignecran)
montecurs ();
// si chaine trouvée
if (trouve)
{
// se positionner sur la ligne de la chaine s'il on n'y est pas déjà
if (i < lignecour)
monte (lignecour - i);
else if (i > lignecour)
descend (i - lignecour);
// réafficher la ligne contenant la chaine en surbrillance
clair ();
affligne (lignecour);
putchar ('\r');
lumnor ();
}
}
/* vérification de la présence d'une chaine dans la numligième ligne */
int dansligne (char *chaine, int numlig)
{
char *maligne; // pour éviter de trop manipuler des indices de tableau
int i, j; // simples compteurs
// initialisation
maligne = ligne [numlig];
i = 0;
// tantque ligne non explorée en entier
while (maligne [i])
{
// si caractère courant = premier caractère de la chaine
if (maligne [i] == *chaine)
{
// vérifier la concordance des caractères suivants
j = 1;
while (chaine [j] && (chaine [j] == maligne [i+j]))
j++;
// si chaine trouvée, sortir de la fonction
if (! chaine [j])
return 1;
}
// sinon, essayer avec la suite de la ligne
i++;
}