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 l'arborescence du répertoire passé
en paramètre, répertoire courant par défaut.
Il est recommandé de lancer cet outils depuis (ou en
passant en paramètre) le répertoire racine des fichiers
mails tel qu'il est défini dans le fichier de configuration
xxxx.cfg
Il est possible de sélectionner l'un des répertoires
affichés pour consulter les fichiers mails qu'il contient
et éventuellement répondre, transférer, ou détruire le message.
Pour ces opérations, cet outil appelle vmailsj
*/
#define appli // pour la déclaration de variables globales à l'application
/*
Par défaut ce programme détecte les noms
de fichiers mails issus de libremail.
Décommenter la ligne qui suit pour accepter
aussi ceux issus de microsoft internet mail.
*/
// #define compat_msoft
/*
Les noms du premier mail envoyé et du premier mail
reçu avec microsoft internet mail sont respectivement
EAAAAAAA et RAAAAAAA.N (RAAAAAAA.R après lecture).
Ensuite, les mails sont numérotés en changeant d'abord
les caractères de droites (36 caractères possibles).
On peut ainsi numéroter 1296 mails sur 2 caractères,
46656 mails sur 3 caractères, plus de 1,6 millions
de mails sur 4 caractères, etc...
La constante nb_a permet de préciser le nombre minimal
de A que l'on veut avoir coté gauche pour qu'un nom de
fichier soit considéré comme celui d'un fichier mail.
*/
#ifdef compat_msoft
#define nb_a 3 // de 0 à 7
#endif
#define max_mdir_ini 100 // nombre max initial de répertoires de mails
#define mdir_accept 50000 // nombre max de répertoires qu'on accepte
#define lg_nomdir 32 // longueur max d'un nom de répertoire
/* type de données */
typedef char nomdir [lg_nomdir];
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
char **maildir; // liste des répertoires de mails
int *nb_mails; // nombre de mails pour chaque répertoire
int *nb_nonlus; // nombre de mails non lus pour chaque répertoire
int max_maildir; // nombre max d'éléments dans maildir, nb_mails, nb_nonlus
int numsortie = 0; // position du répertoire des mails à envoyer
int numpoub = 0; // position du répertoire des mails détruits
int deborde_mem = 0; // mémorise un débordement mémoire
int opt_inv; // option d'inversion de l'ordre d'affichage pour vmailsj
int opt_cn; // options d'affichage du nombre de mails non lus et total
char formatcpt [10]; // format d'affichage du nombre de mails non lus et total
int coldebnomrep; // colonne du début d'afffichage d'un nom de répertoire
// ces deux variables permettent d'éviter des appels répétitifs de ficdir ()
char dir_sortie [szmax_ficdir]; // sous répertoire des mails à envoyer
char dir_poub [szmax_ficdir]; // sous répertoire des mails avant destruction
/* programme principal */
int main (int nbarg, char *varg[])
{
char nomdir [szchemin];
char *ajout;
// récupération du nom de l'exécutable
memcom (*varg);
// se positionner sur le premier argument de vmaildir
varg ++;
nbarg --;
// récupération des options de fonctionnement éventuelles
while (nbarg > 0 && **varg == '-' && varg [0][2] == '\0')
{
switch (varg [0][1])
{
// option inversion de l'ordre d'affichage (pour vmailsj)
case 'i' :
case 'r' : opt_inv = 1;
varg ++;
nbarg --;
break;
// option d'affichage du nombre de mails non lus
case 'n' : if (! opt_cn) // prise en compte si option -c absente
opt_cn = 1;
varg ++;
nbarg --;
break;
// option d'affichage des nombres de mails non lus et total
case 'c' : opt_cn = 2; // prioritaire sur l'option -n
varg ++;
nbarg --;
break;
// récupération éventuelle du nom du répertoire racine des mails
if (nbarg == 1)
{
// se positionner dans ce répertoire
if (chdir (*varg) < 0)
{
// "Répertoire %s inexistant"
aff_err_arg ("REPERT_INEXISTANT", *varg);
return (0);
}
}
// récupérer et mémoriser le nom de 2 sous répertoires importants
strcpy (dir_sortie, ficdir ("DIR_SORTIE"));
strcpy (dir_poub, ficdir ("DIR_POUBELLE"));
// récupérer le chemin d'accès absolu de la racine des mails
getcwd (nomdir, szchemin);
// déterminer le nom du répertoire d'envoi des mails
ajout = nomdir + strlen (nomdir);
*ajout = '/';
strcpy (ajout + 1, dir_sortie);
// et le mémoriser dans une variable d'environnement
setenv ("mailenv", nomdir, 1);
// faire de même avec le répertoire poubelle des fichiers mail
strcpy (ajout + 1, dir_poub);
setenv ("mailpoub", nomdir, 1);
// fixer la taille initiale de la liste des répertoires
max_maildir = max_mdir_ini;
// allouer la liste des répertoires et des compteurs de mails
// (on commence par les tableaux les moins encombrants)
nb_mails = malloc (max_maildir * sizeof (int));
nb_nonlus = malloc (max_maildir * sizeof (int));
maildir = malloc (max_maildir * sizeof (char *));
// vérification allocation
if (! maildir)
// "Manque de place mémoire, le logiciel %s ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", nomcom ());
// mémoriser l'arborescence du répertoire racine des mails
exploredir (".");
// on génère un message en fin de liste si débordement mémoire
if (deborde_mem || max_maildir > mdir_accept)
{
if (nb_lignes + 2 >= max_maildir)
nb_lignes = nb_lignes - 2;
// "Trop de sous répertoires, liste tronquée"
strcpy (nomdir, message ("DEBORD_SOUS_REP"));
maildir [nb_lignes] = nomdir;
nb_mails [nb_lignes] = -1;
nb_nonlus [nb_lignes++] = 1; // pour la surbrillance
}
// si demande d'affichage du nombre de mails (non lus ou/et total)
if (opt_cn)
// préparer le format d'affichage de ces valeurs
gen_format_cpt ();
// vérification de l'accès à ce message avant le passage en mode raw
message ("RACINE_MAILS");
// afficher les répertoire et naviguer dans la liste
navigation ();
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* exploration du répertoire passé en paramètre */
void exploredir (char *repertoire)
{
DIR *repert;
struct dirent *entree;
struct stat descfic;
char nomfic [szchemin]; // chemin d'accès à un fichier
nomdir *listedir; // liste des sous répertoires trouvés
int nbdir_alloc; // nombre de sous repertoires alloués
int nbdir; // nombre de sous repertoires mémorisés
int sznomrep; // longueur du nom de répertoire qu'on analyse
int i; // simple compteur
// si trop de répertoires déjà explorés, on sort
if (max_maildir > mdir_accept)
return;
// accéder au répertoire
repert = opendir (repertoire);
// sortie sur erreur si l'on n'a pas pu
if (repert == 0)
return;
// mémorisation longueur du nom de répertoire
sznomrep = strlen (repertoire);
// mémoriser le chemin d'accès au répertoire
if (nb_lignes == 0)
{
// cas particulier de répertoire racine
maildir [nb_lignes] = ".";
}
// sinon si on peut mémoriser d'autres éléments
else if (ajoutdirpossible ())
{
// cas général : on ne mémorise pas le ./ des noms de sous répertoires
maildir [nb_lignes] = (char *) malloc (strlen (repertoire) - 1);
if (maildir [nb_lignes])
strcpy (maildir [nb_lignes], repertoire + 2);
else
// une erreur mémoire à ce niveau n'est pas facilement récupérable
// "Manque de place mémoire, le logiciel %s ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", nomcom ());
// mémoriser la position des répertoires sortie et poubelle
if (strcmp (repertoire + 2, dir_sortie) == 0)
numsortie = nb_lignes;
else if (strcmp (repertoire + 2, dir_poub) == 0)
numpoub = nb_lignes;
}
// sinon mémoriser un débordement mémoire
else
{
deborde_mem = 1;
return;
}
// initialisation : pas encore de mail trouvé dans ce répertoire
nb_mails [nb_lignes] = 0;
nb_nonlus [nb_lignes] = 0;
// récupérer le nombre de liens du répertoire
stat (repertoire, &descfic);
// et allouer le bon nombre d'entrées dans la liste des
// sous répertoires avec une sécurité de 2 (correspondant
// à . et ..) pour éviter erreur de segmentation
nbdir_alloc = descfic.st_nlink;
listedir = (nomdir *) calloc (nbdir_alloc, lg_nomdir);
if (! listedir)
{
deborde_mem = 1;
return;
}
// aucun sous répertoire encore mémorisé
nbdir = 0;
// lire un nom de fichier ou de répertoire
entree = readdir (repert);
// tant qu'il y a des noms de fichier ou de répertoires à lire
while (entree)
{
// si le nom ne commence pas par un .
// (évitera de boucler sur les répertoires . et ..)
// et qu'il n'est pas trop long
if (entree->d_name [0] != '.' &&
(sznomrep + strlen (entree->d_name) < szchemin))
{
// récupérer les caractéristiques du fichier courant
sprintf (nomfic, "%s/%s", repertoire, entree->d_name);
stat (nomfic, &descfic);
// on ne mémorisera que les noms des répertoires
if ((descfic.st_mode & S_IFMT) == S_IFDIR)
{
// tronquer les noms à 32 caractères
if (strlen (entree->d_name) >= lg_nomdir)
entree->d_name [lg_nomdir - 1] = '\0';
// précaution pour éviter un débordement de tableau
if (nbdir >= nbdir_alloc)
listedir = maj_espace (listedir, &nbdir_alloc);
// mémoriser le nom du sous répertoire
strcpy (listedir [nbdir ++], entree->d_name);
}
// et la présence de fichiers mail déjà lus ou en attente de lecture
else if (fichier_mail (entree->d_name))
{
nb_mails [nb_lignes] ++;
// test si mail en attente de lecture
if (entree->d_name [8] == '.' &&
tolower (entree->d_name [9]) == 'n')
{
nb_nonlus [nb_lignes] ++;
}
}
}
// et lire le nom du fichier suivant
entree = readdir (repert);
}
// libérer le répertoire
closedir (repert);
// mettre à jour le compteur
nb_lignes ++;
// tri alphabétique des noms de sous répertoires
trinoms (listedir, nbdir - 1);
// exploration des sous répertoires trouvés
for (i = 0; i < nbdir; i++)
{
sprintf (nomfic, "%s/%s", repertoire, listedir [i]);
exploredir (nomfic);
}
// libération de l'espace mémoire du tableau listedir
free (listedir);
}
/* vérifie si l'on peut insérer un élément de plus dans le tableau
maildir, et redimmensionne ce tableau si nécessaire */
int ajoutdirpossible ()
{
char **nouvmaildir; // adresse du tableau maildir de remplacement
int *nouv_nbmails; // adresse du tableau nb_mails de remplacement
int *nouv_nbnonlus; // adresse du tableau nb_nonlus 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 < max_maildir)
return (1);
// calculer la nouvelle taille des tableaux
// l'augmentation est alternativement de 50 % ou 33 % de manière
// à ce que la taille double après 2 réallocations
if (max_maildir % 3)
nouvtaille = max_maildir + (max_maildir / 2);
else
nouvtaille = max_maildir + (max_maildir / 3);
// que l'on remplace par les nouveaux
maildir = nouvmaildir;
nb_mails = nouv_nbmails;
nb_nonlus = nouv_nbnonlus;
max_maildir = nouvtaille;
}
// retourne le résultat de la possibilité d'insertion d'éléments
return (nb_lignes + 1 < max_maildir);
}
/* détermine si un nom de fichier passé en paramètre
correspond à un nom de fichier mail */
int fichier_mail (char *nomfic)
{
char car; // pour éviter de trop manipuler des tableaux
int i; // compteur
// test du premier caractère du nom de fichier
car = tolower (nomfic [0]);
// si le nom de fichier commence par l'une des bonnes lettres possibles
if (car == 'r' || car == 'e'
#ifdef compat_msoft
|| car == 's'
#endif
)
// on va examiner les caractères qui suivent
i = 1;
else
// sinon ce n'est pas un fichier mail
return 0;
// test des caractères qui suivent
while (i < 8)
{
#ifdef compat_msoft
car = tolower (nomfic [i]);
#else
car = nomfic [i];
#endif
// si le ième caractère est bon
if (('0' <= car && car <= '9')
#ifdef compat_msoft
|| (car == 'a')
|| (i >= nb_a && 'b' <= car && car <= 'z')
#endif
)
// examiner le caractère suivant
i++;
else
// sinon ce n'est pas un fichier mail
return 0;
}
// le si nom de fichier fait 8 caractères
if (nomfic [8] == '\0')
// il s'agit d'un nom de fichier mail
return 1;
// sinon si le 9ème caractère est un . et qu'il y a 10 caractères en tout
else if (nomfic [8] == '.' && nomfic [10] == '\0')
{
// examiner le dernier caractère
car = tolower (nomfic [9]);
if (car == 'n')
return 1; // fichier mail reçu et non encore lu
#ifdef compat_msoft
else if (car == 'r')
return 1; // fichier micro$oft internet mail déjà lu
#endif
else
return 0; // ce n'est pas un fichier mail
}
else
// sinon ce n'est pas un fichier mail
return 0;
}
/* augmentation de la taille d'une liste de sous répertoires */
nomdir * maj_espace (nomdir * oldliste, int * taille)
{
nomdir *newliste; // nouveau tableau
// allocation d'un tableau plus grand
newliste = (nomdir *) calloc (*taille + 4, lg_nomdir);
// controle
if (! newliste)
// "Manque de place mémoire, l'application ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", NULL);
// retour de la nouvelle adresse et taille du tableau
*taille = *taille + 4;
return (newliste);
}
/* tri alphabétique des noms de sous répertoires */
void trinoms (nomdir *liste, int fin)
{
char tampon [lg_nomdir]; // chaine de caractères pour permutation
int i; // indice dans la liste
// initialisation
i = 0;
while (i < fin)
{
// on compare 2 éléments consécutifs
if (strcmp (liste [i], liste [i+1]) > 0)
{
// interversion de 2 noms
strcpy (tampon, liste [i]);
strcpy (liste [i], liste [i+1]);
strcpy (liste [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 la liste des sous répertoire et permet de
la parcourir même si elle tient sur plusieurs pages */
void navigation ()
{
int car; // caractère tapé au clavier
int erreurs; // nombre frappes caractères inconnus comme commandes
// 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"
// "v, l ou entrée pour Voir (Lire)"
// "les mails du répertoire"
// "n ou Inser pour en créer un Nouveau"
// "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_VMAILDIR-1");
affiche_msg ("AIDE_VMAILDIR-2");
affiche_msg ("AIDE_VMAILDIR_SJ");
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 ();
// pas de break, on réaffiche la page
case CTRL : affpage ();
erreurs = 0;
break;
case 'l' :
case 'v' : // ici, on regarde les descriptifs des mails
case '\n' : if (opt_inv)
execom ("vmailsj -i", maildir [lignecour]);
else
execom ("vmailsj", maildir [lignecour]);
// maj du mode d'affichage des répertoires
detectemail (lignecour);
detectemail (numsortie);
detectemail (numpoub);
case INSERT : // création d'un nouveau mail
case 'n' : execom ("cremail", " ");
// maj du mode affichage répertoire mails à envoyer
detectemail (numsortie);
// réafficher la page d'écran
affpage ();
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);
// descendre en bas de page
while (lignecran++ < lignepage && lignecour++ < nb_lignes)
putchar ('\n');
// retour à la configuration standard du clavier
mode_normal ();
}
/* recherche de fichiers mail dans le répertoire passé en paramètre */
void detectemail (int numrep)
{
DIR *repert;
struct dirent *entree;
struct stat descfic;
char nomfic [szchemin]; // chemin d'accès à un fichier
// accéder au répertoire
repert = opendir (maildir [numrep]);
// sortie sur erreur si l'on n'a pas pu
if (repert == 0)
return;
// initialisation : pas encore de mail trouvé dans ce répertoire
nb_mails [numrep] = 0;
nb_nonlus [numrep] = 0;
// lire un nom de fichier
entree = readdir (repert);
// tant qu'il y a des noms de fichier à lire
while (entree)
{
// récupérer les caractéristiques du fichier courant
sprintf (nomfic, "%s/%s", maildir [numrep], entree->d_name);
stat (nomfic, &descfic);
// si c'est un fichier mail
if ((descfic.st_mode & S_IFMT) == S_IFREG
&& fichier_mail (entree->d_name))
{
nb_mails [numrep] ++;
// test si mail en attente de lecture
if (entree->d_name [8] == '.' &&
tolower (entree->d_name [9]) == 'n')
{
nb_nonlus [numrep] ++;
}
}
// et lire le nom du fichier suivant
entree = readdir (repert);
}
// libérer le répertoire
closedir (repert);
}
/* génère le format d'affichage du nombre de mails non lus
et éventuellement du nombre total de mails */
void gen_format_cpt ()
{
int max_nbmails = 0;
int max_nonlus = 0;
int puis10;
int col_nl, col_m;
int i;
// chercher le plus grand nombre de mails non lus
// parmi tous les répertoires mémorisés
for (i = 0; i < nb_lignes; i++)
if (nb_nonlus [i] > max_nonlus)
max_nonlus = nb_nonlus [i];
// calculer le nombre de chiffres pour afficher ce nombre
puis10 = 10;
col_nl = 1;
// si on doit afficher aussi le nombre total de mails
if (opt_cn > 1)
{
// chercher le plus grand nombre de mails
// parmi tous les répertoires mémorisés
for (i = 0; i < nb_lignes; i++)
if (nb_mails [i] > max_nbmails)
max_nbmails = nb_mails [i];
// calculer le nombre de chiffres pour afficher ce nombre
puis10 = 10;
col_m = 1;
// générer le format d'affichage des 2 nombres
sprintf (formatcpt, "%%%dd/%%-%dd ", col_nl, col_m);
// et mémoriser la largeur de cet affichage
coldebnomrep = col_nl + col_m + 2;
}
// sinon
else
{
// générer le format d'affichage du nombre de mails non lus
sprintf (formatcpt, "%%%dd ", col_nl);
// et mémoriser la largeur de cet affichage
coldebnomrep = col_nl + 1;
}
}
/* affiche le nom de répertoire passé en
paramètre sans déborder de la fenêtre */
void affligne (int numlig)
{
int i;
char *carcourant;
// positionnement au début du nom de répertoire
if (strcmp (maildir [numlig], ".") == 0)
// cas particulier du répertoire racine
// "<racine>"
carcourant = message ("RACINE_MAILS");
else
// cas général
carcourant = maildir [numlig];
// afficher en bleu foncé les répertoires sans mail
if (!nb_mails [numlig])
sombre ();
// et en surbrillance ceux qui ont des mails non lus
else if (nb_nonlus [numlig])
clair ();
// si demandé, afficher les nombres de mails
if (opt_cn)
printf (formatcpt, nb_nonlus [numlig], nb_mails [numlig]);
// initialisation numéro de colonne d'affichage
i = coldebnomrep;
// on arrête l'affichage en fin de chaine ou en bord de fenêtre
while (*carcourant && i++ < colonpage)
{
putchar (*carcourant);
carcourant ++;
}
// retour à l'affichage en luminosité normale
lumnor ();
}