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 les caractéristique de chaque mail
mémorisé dans un fichier.
Il y a 2 formats d'affichage.
Le format détaillé (option -d) donne plusieurs lignes d'information :
- date et heure d'envoi
- expéditeur et destinataire(s) + éventuelle adresse de réponse
- sujet du mail
- format du message (texte, html ...)
- éventuellement premières lignes du message
Le format simplifié (option -s) affiche une ligne par message :
expéditeur sujet date et heure d'envoi
destinataire sujet date et heure d'envoi
selon qu'il s'agisse d'un mail reçu ou envoyé (ou à envoyer)
Par défaut, on analyse les mails du répertoire courant.
On peut aussi indiquer un autre répertoire de recherche.
*/
#define appli // pour la déclaration de variables globales à l'application
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
int nblig_mes; // nombre de lignes à afficher pour chaque message
descmail *fichmail; // noms des fichiers mail
int nbmails; // nombre de fichiers mail mémorisés
int maxnbmails; // nombre maximum de fichiers mail mémorisés
int opt_aff; // option affichage (simple = -s, détaillé = -d)
int opt_inv; // option inversion de l'ordre d'affichage des mails
int opt_n; // options pour l'affichage des mails non lus
int sz_nom, sz_avantdate; // largeur des champs affichés si option -s
int test_xorig; // traitement ou non du champ X-Original-From
/* programme principal */
int main (int nbarg, char *varg[])
{
int largeur; // largeur de l'affichage si option -s
char *dirmails;
// récupération du nom de l'exécutable
memcom (*varg);
// se positionner sur le premier argument de sjfmails
varg ++;
nbarg --;
// initialisation options de fonctionnement
opt_aff = 0;
opt_inv = 0;
opt_n = 0;
nblig_mes = 0;
largeur = 0; // la valeur sera fixée plus tard
// récupération des options de fonctionnement éventuelles
while (nbarg > 0 && **varg == '-' && varg [0][2] == '\0')
{
switch (varg [0][1])
{
// option affichage détaillé
case 'd' : opt_aff = 1;
varg ++;
nbarg --;
// récupérer le nombre de lignes
// après entête s'il y a lieu
if (nbarg > 0)
{
nblig_mes = atoi (*varg);
if (nblig_mes)
{
varg ++;
nbarg --;
}
}
break;
// option largeur de l'affichage simplifié
case 'w' : varg ++;
nbarg --;
// récupération de la largeur de l'affichage
largeur = atoi (*varg);
// option inversion de l'ordre d'affichage
case 'i' :
case 'r' : opt_inv = 1;
varg ++;
nbarg --;
break;
// option -n pour mettre en évidence les mails non lus
// ou option -N pour n'afficher que les mails non lus
case 'n' :
case 'N' : opt_n = varg [0][1];
varg ++;
nbarg --;
break;
// rappeller la syntaxe de la commande
psyntaxe ("SYNT_SJFMAILS");
}
}
// valeur par défaut de la largeur d'affichage si elle n'a pas été fixée
if (! largeur)
largeur = 80;
// calcul de la taille des différentes zones d'affichage si option -s
sz_nom = (largeur / 4) - 1;
sz_avantdate = largeur - 13;
// correction si option -n
if (opt_n == 'n')
sz_nom ++;
// récupération éventuelle du nom du répertoire des mails
if (nbarg == 1)
{
dirmails = *varg;
// positionnement dans ce répertoire
if (chdir (dirmails) < 0)
{
// "Répertoire %s inexistant"
aff_err_arg ("REPERT_INEXISTANT", dirmails);
return (0);
}
}
// si aucune erreur dans la liste des paramètres
if (nbarg < 2)
{
// fixer la taille initiale de la liste des fichiers mail
maxnbmails = max_nbmail_ini;
// allouer la liste des fichiers mail
fichmail = malloc (12 * maxnbmails);
// vérification allocation
if (! fichmail)
// "Manque de place mémoire, le logiciel %s ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", nomcom ());
// récupération de la liste des fichiers mail
lister_mails ();
// ordonnés par noms de fichiers
trinoms ();
// affichage détaillé ou résumé de l'entête des mails
affiche_liste ();
}
else
// "Syntaxe : %s [-(s|d [nb_lignes_messages])]
// [-w largeur] [-i] [-(n|N)] [répertoire_fichiers]"
psyntaxe ("SYNT_SJFMAILS");
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* récupère le nombre de mails */
void lister_mails ()
{
DIR *repert;
struct dirent *entree;
int debordement;
char *varenv_xorig;
// initialisation
nbmails = 0;
debordement = 0;
// déterminer si on va traiter les champs X-Original-From
varenv_xorig = getenv ("libremail_xorig");
// lire un nom de fichier
entree = readdir (repert);
// tant qu'il y a des noms de fichier à lire
while (entree)
{
// vérifier le nom du fichier
if ((strlen (entree->d_name) == 8 && opt_n != 'N') ||
(strlen (entree->d_name) == 10 && entree->d_name [8] == '.'))
{
// si on ne peut pas rajouter des fichiers dans la liste
if (! ajoutlistepossible ())
{
// si c'est la première fois
if (! debordement)
{
// message d'avertissement
// "Manque de place mémoire, ordre des fichiers mail non respecté"
affiche_msg ("DEBORD_NBMAXFIC");
// qu'on n'affichera pas plusieurs fois
debordement = 1;
}
// ordonner les noms de fichiers mail déjà mémorisés
trinoms ();
// affichage détaillé ou résumé de l'entête de ces mails
affiche_liste ();
// on recommence avec une liste vide pour continuer
nbmails = 0;
}
// mémoriser le nom
strcpy (fichmail [nbmails++], entree->d_name);
}
// et lire le nom du fichier suivant
entree = readdir (repert);
}
}
/* vérifie si l'on peut insérer un nom de fichier de plus dans le
tableau fichmail, et redimmensionne ce tableau si nécessaire */
int ajoutlistepossible ()
{
descmail *nouvtableau; // adresse du tableau de remplacement
int nouvtaille; // et sa taille
int element; // numéro d'élément dans les tableaux
int numcar; // numéro de caractère dans un nom de fichier
// cas simple : il reste au moins une place de libre dans le tableau
if (nbmails + 1 < maxnbmails)
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 (maxnbmails % 3)
nouvtaille = maxnbmails + (maxnbmails / 2);
else
nouvtaille = maxnbmails + (maxnbmails / 3);
// vérification allocation
if (nouvtableau)
{
// copie du contenu de l'ancien tableau dans le nouveau
for (element = 0; element < maxnbmails; element ++)
for (numcar = 0; numcar < 12; numcar ++)
nouvtableau [element][numcar] = fichmail [element][numcar];
// destruction de l'ancien tableau
free (fichmail);
// que l'on remplace par le nouveau
fichmail = nouvtableau;
maxnbmails = nouvtaille;
}
// retourne le résultat de la possibilité d'insertion d'éléments
return (nbmails + 1 < maxnbmails);
}
/* tri alphabétique des noms de fichiers mail */
void trinoms ()
{
char tampon [12]; // chaine de caractères pour permutation
char carfic1, carfic2; // caractère de 2 noms de fichiers que l'on compare
int i; // indice dans la liste
int j; // numéro de caractère des noms de fichiers
// initialisation
i = 0;
// tant que la liste des noms de fichiers n'a pas été parcourue en entier
while (i < nbmails - 1)
{
// positionnement sur le premier caractère du numéro d'ordre
j = 1;
// tant qu'on a le même caractère dans les 2 fichiers
while (fichmail [i][j] == fichmail [i+1][j])
// passer au caractère suivant
j++;
// si un caractère est une lettre, (fichier issu de Micro$oft Internet
// mail), on le fait passer avant les chiffres dans la numérotation
if (fichmail [i][j] & 0x40)
// lettre codée de 01h à 1Ah après transformation
carfic1 = fichmail [i][j] & 0x1F;
else
// chiffre codé de 30h à 39h conservé tel quel
carfic1 = fichmail [i][j];
// on compare 2 éléments consécutifs
if (carfic1 > carfic2)
{
// interversion de 2 noms
strcpy (tampon, fichmail [i]);
strcpy (fichmail [i], fichmail [i+1]);
strcpy (fichmail [i+1], tampon);
// ce qui peut supposer de comparer un nom déplacé avec le précédent
if (i > 0)
i--;
else
i++;
}
else
i++; // on progresse dans la liste
}
}
/* affiche les informations concernant les fichiers mails mémorisés */
void affiche_liste ()
{
int numail;
// affichage détaillé ou résumé de l'entête des mails
if (opt_aff)
{
// l'ordre d'affichage dépend de l'option -i éventuelle
if (opt_inv)
{
for (numail = nbmails -1; numail >= 0; numail--)
aff_detail (fichmail [numail]);
}
else
{
for (numail = 0; numail < nbmails; numail++)
aff_detail (fichmail [numail]);
}
}
else
{
if (opt_inv)
{
for (numail = nbmails -1; numail >= 0; numail--)
aff_resume (fichmail [numail]);
}
else
{
for (numail = 0; numail < nbmails; numail++)
aff_resume (fichmail [numail]);
}
}
}
/* lit l'entête d'un mail et affiche certaines lignes */
void aff_detail (char *nomfic)
{
// buffers pour affichage ordonné des caractéristiques du message
char bufFrom [120], bufTo [120], bufCc [120], bufReply [120],
bufSubject [120], bufContent [120], bufXorig [120];
int date_ok; // indique si le champ date a été lu
int i, j; // simples compteurs
// ouverture du fichier mail
fmail = fopen (nomfic, "r");
// arrêt si erreur imprévue
if (fmail == 0)
{
// "Impossible d'ouvrir le fichier %s"
aff_err_arg ("IMPOS_OUVR_FICH", nomfic);
return;
}
// tantqu'on peut lire une ligne de l'entête du mail
while (lire_fmail () && buf_lect [0] != '\0')
{
// si la ligne correspond au champ sujet
if (start ("Subject"))
{
// mémoriser la ligne
memconvbuf (bufSubject);
// on va tester la ligne qui suit
lire_fmail ();
majlignentete ();
// si c'est encore une ligne du sujet
if (*buf_lect == ' ' || *buf_lect == '\t')
{
// initialisation compteurs
i = 1;
j = strlen (bufSubject);
// compléter le sujet du mail
while (buf_lect [i] && j < sizeof (bufSubject) - 1)
bufSubject [j++] = buf_lect [i++];
// terminer la chaine de caractères
bufSubject [j] = '\0';
}
}
// mémorisation des autres caractéristiques importantes
if (start ("Date"))
{
// pas la peine de mémoriser la date si on l'affiche en premier
// "Fichier mail %s\n"
printf (message ("AFF_NOM_FICMAIL"), nomfic);
puts (buf_lect);
date_ok = 1; // on sait que c'est un fichier mail
}
else if (start ("From"))
memconvbuf (bufFrom);
else if (start ("X-Original-From") && test_xorig)
memconvbuf (bufXorig);
else if (start ("To"))
memconvbuf (bufTo);
else if (start ("Cc"))
memconvbuf (bufCc);
else if (start ("Reply-To"))
memconvbuf (bufReply);
else if (start ("Content-Type"))
{
membuf (bufContent);
if (recup_ctype () == TextPlain)
lire_charset ();
}
else if (start ("Content-Transfer-Encoding"))
mem_encodage ();
}
// si l'on n'a pas trouvé de ligne Date: From: ou Subject:
if (! date_ok && ! *bufFrom && ! *bufSubject)
return; // ce n'est pas un fichier mail
// affichage des caractéristiques mémorisées
if (bufFrom [0])
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);
if (bufContent [0])
puts (bufContent);
// lecture et affichage du début du message
i = 0;
while (i++ < nblig_mes && lire_fmail ())
{
// on prend en compte les nouveaux champs Content éventuels
if (start ("Content-Type") && recup_ctype () == TextPlain)
lire_charset ();
else if (start ("Content-Transfer-Encoding"))
mem_encodage ();
// convertir la ligne lue et l'afficher
majligne ();
printf ("%s", buf_lect);
}
putchar ('\n');
// libérer le fichier mail
fclose (fmail);
}
/* lit l'entête d'un mail et affiche un résumé sur une ligne */
void aff_resume (char *nomfic)
{
// buffers pour mémoriser les caractéristiques principales du message
char bufFromTo [120], bufSubject [120], bufDate [120];
// les noms de mois dans les champs Date: des mails
static char *mois [] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
int affichedest; // indique si on doit afficher le champ destinataire
int i, j; // simples compteurs
// ouverture du fichier mail
fmail = fopen (nomfic, "r");
// arrêt si erreur imprévue
if (fmail == 0)
{
// "Impossible d'ouvrir le fichier %s"
aff_err_arg ("IMPOS_OUVR_FICH", nomfic);
return;
}
// déterminer le champ à afficher entre expéditeur et destinataire
affichedest = (tolower (*nomfic) == 'e') || (tolower (*nomfic) == 's');
// tantqu'on peut lire une ligne de l'entête du mail
while (lire_fmail () && buf_lect [0] != '\0')
{
// si la ligne correspond au champ sujet
if (start ("Subject"))
{
// mémoriser la ligne
memconvbuf (bufSubject);
// on va tester la ligne qui suit
lire_fmail ();
majlignentete ();
// si c'est encore une ligne du sujet
if (*buf_lect == ' ' || *buf_lect == '\t')
{
// initialisation compteurs
i = 1;
j = strlen (bufSubject);
// compléter le sujet du mail
while (buf_lect [i] && j < sizeof (bufSubject) - 1)
bufSubject [j++] = buf_lect [i++];
// terminer la chaine de caractères
bufSubject [j] = '\0';
}
}
// mémorisation des autres caractéristiques importantes
if (start ("Date"))
membuf (bufDate);
else if (start ("From") && ! affichedest && ! *bufFromTo)
memconvbuf (bufFromTo);
else if (start ("X-Original-From") && test_xorig)
memconvbuf (bufFromTo);
else if (start ("To") && affichedest)
memconvbuf (bufFromTo);
}
// si l'on n'a pas trouvé de ligne Date: From: ou Subject:
if (! *bufDate && ! *bufFromTo && ! *bufSubject)
return; // ce n'est pas un fichier mail
// si on doit afficher l'information sur les mails non lus
if (opt_n == 'n')
{
// le faire
if (strlen (nomfic) == 10 && nomfic [8] == '.')
putchar ('N');
else
putchar (' ');
putchar (' ');
// déjà 2 caractères écrits dans la ligne
i = 2;
}
// sinon
else
// on est en début de ligne
i = 0;
// affichage du nom de l'expéditeur ou du destinataire du message
if (*bufFromTo)
{
// sauter le mot clé From: , To: ou X-Original-From:
if (affichedest)
j = 4;
else if (tolower (*bufFromTo) == 'x')
j = 16;
else
j = 6;
// si affichage avec un jeu de caractères ISO-8859
if (! util_utf8 ())
{
// on affichera sz_nom caractères maximum
while (++i < sz_nom && bufFromTo [j] && bufFromTo [j] != '<'
&& bufFromTo [j] != '"' && bufFromTo [j] != '=')
putchar (bufFromTo [j++]);
}
// sinon (affichage avec le jeu de caractères UTF-8)
else
{
// on affichera toujours sz_nom caractères maximum
while (++i < sz_nom && bufFromTo [j] && bufFromTo [j] != '<'
&& bufFromTo [j] != '"' && bufFromTo [j] != '=')
{
// mais certains caractères ne seront pas comptés
/* il serait plus logique de ne pas compter les caractères
entre 0x80 et 0xBF, mais certains caractères UTF8 codés
sur 3 (ou 4 ?) octets s'affichent en largeur double, ce
qui décale les autres colonnes et génère un saut de ligne
intempestif après la date */
if ((bufFromTo [j] & 0xC0) == 0xC0)
i--;
putchar (bufFromTo [j++]);
}
}
}
// complété par des blancs
while (i++ <= sz_nom)
putchar (' ');
// affichage du sujet du message
if (*bufSubject)
{
j = 8;
// on saute les blancs inutiles
while (bufSubject [j] == ' ')
j++;
// si affichage avec un jeu de caractères ISO-8859
if (! util_utf8 ())
{
// on affichera jusqu'à sz_avantdate caractères maximum
while (++i < sz_avantdate && bufSubject [j])
{
// si présence d'une tabulation
if (bufSubject [j] == '\t')
{
// afficher un blanc pour une meilleure mise en page
putchar (' ');
j++;
}
else
// sinon affichage du caractère
putchar (bufSubject [j++]);
}
}
// sinon (affichage avec le jeu de caractères UTF-8)
else
{
// on affichera jusqu'à sz_avantdate caractères maximum
while (++i < sz_avantdate && bufSubject [j])
{
// si présence d'une tabulation
if (bufSubject [j] == '\t')
{
// afficher un blanc pour une meilleure mise en page
putchar (' ');
j++;
}
// sinon affichage du caractère
else
{
// mais certains caractères ne seront pas comptés
// même remarque que pour bufFromTo
if ((bufSubject [j] & 0xC0) == 0xC0)
i--;