#define szbufadr 120 // longueur max d'une adresse dans le carnet
#define octet unsigned char
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
static char **adresse; // les adresses de destinataires
static octet *selection; // indique si le destinataire a été sélectionné
/* recupère le nom du répertoire des mails à envoyer */
void recupdirenv (int nbarg, char *arg2)
{
// récupérer le nom du répertoire des fichiers mail à envoyer
if (getenv ("mailenv"))
// récupération dans variable environnement créée par vmaildir
strcpy (direnv, getenv ("mailenv"));
else
{
if (nbarg == 2)
// récupération dans 2ème argument passé à la commande
strcpy (direnv, arg2);
else
{
// il ne reste plus que la saisie au clavier
// "Nom du répertoire racine des mails : "
affiche_msg_nocr ("REPERT_RACINE");
fgets (direnv, szchemin, stdin);
// à cause du \n retourné par fgets
direnv [strlen (direnv) - 1] = '\0';
}
// si nom du répertoire racine correct
if (access (direnv, 0) == 0)
{
// fabriquer le nom du répertoire des mails à envoyer
strcat (direnv, "/");
strcat (direnv, ficdir ("DIR_SORTIE"));
}
else
// sinon, terminé sur erreur
// "Répertoire %s inexistant"
errfatale ("REPERT_INEXISTANT", direnv);
}
// créer le répertoire d'envoi des mails si nécessaire
mkdir (direnv, 0755);
// s'il existe, on continue
if (access (direnv, 0) < 0)
// "Le répertoire %s n'a pu être créé"
errfatale ("REPERT_NON_CREE", direnv);
}
/* rajoute un champ Message-Id à l'entête du mail */
void gen_mes_id (FILE *ficentete, long numail, char *adr_exped)
{
int i; // compteur
// parcour de l'adresse de l'expéditeur
i = 0;
// recherche du champ adresse
while (adr_exped [i] && adr_exped [i] != '@')
i++;
// on se positionne au début de l'adresse
while (i >= 0 && adr_exped [i] != '<' && adr_exped [i] != ' ')
i--;
// générer la ligne Message-Id
fprintf (ficentete, "Message-Id: <%ld-%s>\n", numail, adr_exped + i + 1);
}
/* rajoute la date et l'heure courante à la fin de l'entête du mail
Le champ Date: généré tient compte du réglage le plus fréquent sur
les ordinateurs européens : l'ordinateur est réglé sur l'heure locale.
*/
void ajout_date (char *nomfic)
{
char commande [szchemin + 42]; // la commande que l'on va exécuter
// revenir à la langue de Bill Gates utilisée pour les mails
unsetenv ("LANG");
unsetenv ("LANGUAGE");
unsetenv ("LC_TIME");
unsetenv ("LC_ALL");
// rajouter la date avec le bon format dans le fichier
// le fuseau horaire est indiqué en chiffres, mais pas en lettres
sprintf (commande, "date \"+%s\" >> %s", "Date: %a, %d %b %Y %T %z",nomfic);
system (commande);
}
/* réunit les 2 morceaux du mail et donne au fichier mail son nom définitif */
void fusionner (char *entete, long numail, char *message)
{
FILE *fentet, *fmess; // descripteurs des 2 fichiers
int car; // caractère du corps du mail
// ouvrir les 2 fichiers dans le bon mode
fentet = fopen (entete, "a");
if (! fentet)
// "Impossible de compléter l'entête du message %s"
errfatale ("IMPOS_MAJ_ENTETE", entete);
fmess = fopen (message, "r");
if (! fmess)
// "Impossible de relire le corps du message %s"
errfatale ("IMPOS_LIRE_MSG", message);
// saut de ligne obligatoire entre l'entête et le message
putc ('\n', fentet);
// copie des données (on rajoute le message à l'entête)
car = getc (fmess);
while (car != EOF)
{
putc (car, fentet);
car = getc (fmess);
}
// fermer les fichiers
fclose (fmess);
fclose (fentet);
// on peut détruire le fichier temporaire qui contenait le message
unlink (message);
// donner au fichier mail son nom définitif
sprintf (message, "%s/e%07ld", direnv, numail);
rename (entete, message);
}
/* ajoute la signature éventuelle à un mail */
void ajout_sign (char *message)
{
char fic_sign [szchemin]; // fichier contenant la signature de l'expéditeur
char *car_fic_sign; // pointeur sur un caractère de ce fichier
FILE *fmess, *fsign; // descripteur des fichiers message et signature
int car, carsuiv; // caractères de la signature
int suiv_lu = 0; // indique si on a lu le caractère suivant
// fabriquer le nom du fichier signature
strcpy (fic_sign, direnv);
car_fic_sign = fic_sign + strlen (direnv) - strlen (ficdir ("DIR_SORTIE"));
strcpy (car_fic_sign, ficdir ("FIC_SIGNATURE"));
// essayer d'ouvrir ce fichier en lecture
fsign = fopen (fic_sign, "r");
// si le fichier signature a pu être ouvert
if (fsign)
{
// ouvrir le fichier contenant le mail en écriture fin de fichier
fmess = fopen (message, "a");
// terminé si problème à l'ouverture
if (!fmess)
{
// "Fichier mail protégé en écriture"
affiche_err ("ACCES_FICHMAIL_ECR");
montecurs ();
attendre (2);
return;
}
// rajout d'une séparation avant la signature
fputs ("--------------------------------\n", fmess);
// copie de la signature
car = getc (fsign);
// si on travaille avec le jeu de caractères UTF-8
if (util_utf8 ())
{
// tant que non fin de fichier
while (car != EOF)
{
// si le caractère lu est un caractère ASCII
if ((car & 0x80) == 0)
// recopier ce caractère
putc (car, fmess);
// sinon si ce caractère est dans l'intervalle 0x80 - 0xBF
else if ((car & 0x40) == 0)
{
// générer la séquence UTF-8 correspondante
putc (0xC2, fmess);
putc (car, fmess);
}
// sinon ça peut être le début d'une séquence UTF-8
else
{
// lire le caractère suivant
carsuiv = getc (fsign);
// si c'est le 2ème caractère d'une séquence UTF-8
if ((carsuiv & 0xC0) == 0x80)
{
// recopier la séquence UTF-8
putc (car, fmess);
putc (carsuiv, fmess);
// si elle n'est pas finie
if ((car & 0xE0) == 0xE0)
{
// lire et recopier la fin de la séquence
// sans la tester
putc (getc (fsign), fmess);
if ((car & 0xF0) == 0xF0)
putc (getc (fsign), fmess);
}
}
// sinon
else
{
// convertir le premier caractère en UTF-8
putc (0xC3, fmess);
putc (car - 0x40, fmess);
// le caractère suivant est déjà lu
car = carsuiv;
suiv_lu = 1;
}
}
// lire le caractère suivant si nécessaire
if (suiv_lu)
suiv_lu = 0;
else
car = getc (fsign);
}
}
// sinon on travaille avec un jeu de caractères ISO-8859
else
{
// tant que non fin de fichier
while (car != EOF)
{
// si le caractère lu n'est pas le début d'une
// séquence UTF-8 qu'on peut convertir en ISO-8859-1
if (car != 0xC2 && car != 0xC3)
// recopier le caractère
putc (car, fmess);
// sinon
else
{
// lire le caractère suivant
carsuiv = getc (fsign);
// si c'est le 2ème caractère d'une séquence UTF-8
if ((carsuiv & 0xC0) == 0x80)
{
// afficher le caractère ISO-8859-1 correspondant
if (car == 0xC2)
putc (carsuiv, fmess);
else
putc (carsuiv | 0x40, fmess);
}
// sinon
else
{
// recopier le premier caractère
putc (car, fmess);
// le suivant est déjà lu
car = carsuiv;
suiv_lu = 1;
}
}
// lire le caractère suivant si nécessaire
if (suiv_lu)
suiv_lu = 0;
else
car = getc (fsign);
}
}
// fermer les fichiers
fclose (fmess);
fclose (fsign);
}
// sinon si le fichier signature existait quand même
else if (access (fic_sign, 0) == 0)
{
// message d'avertissement
// "Fichier signature %s protégé en lecture"
aff_err_arg ("FICH_SIGN_PROTLECT", fic_sign);
montecurs ();
attendre (2);
}
}
/* charge en mémoire le contenu du carnet d'adresse */
void charge_carnet_adr ()
{
char ficadr [szchemin]; // fichier contenant le carnet d'adresse
FILE *fadr; // descripteur du fichier carnet d'adresse
char buf_adr [szbufadr]; // buffer pour lecture d'une adresse du carnet
char *ligne_adr; // ligne du carnet d'adresse à mémoriser
int i, taille; // compteur + longueur ligne à mémoriser
// initialisation : aucune adresse encore mémorisée
nb_lignes = 0;
// trouver le nom du fichier carnet d'adresse et l'ouvrir en lecture
strcpy (ficadr, direnv);
strcpy (ficadr + strlen (direnv) - 6, ficdir ("FIC_CARNET-ADR"));
fadr = fopen (ficadr, "r");
// si ce carnet d'adresse existe
if (fadr)
{
// compter le nombre de lignes qu'il contient
while (fgets (buf_adr, szbufadr, fadr))
nb_lignes ++;
// allouer la zone mémoire pour mémoriser ces lignes
// la taille de la liste allouée est optimale (sauf si lignes
// sans adresse Email valide) et non limitée à la compilation
adresse = malloc (nb_lignes * sizeof (char *));
// et la liste des lignes sélectionnées par l'utilisateur
selection = malloc (nb_lignes);
if ((! adresse) || (! selection))
// "Manque de place mémoire, l'application ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", NULL);
// on revient au début du fichier
rewind (fadr);
// réinitialisation du compteur de lignes
// on ne mémorisera que les lignes avec un @ (adresse Email valide)
nb_lignes = 0;
// récupérer et mémoriser les différentes lignes du carnet d'adresses
while (fgets (buf_adr, szbufadr, fadr))
{
taille = strlen (buf_adr) - 1;
// supprimer les blancs ou parasites en fin de ligne
while (taille > 0 && buf_adr [taille] <= ' ')
taille --;
// tester la validité de l'adresse
for (i = 0; i < taille; i++)
if (buf_adr [i] == '@')
break;
// si adresse valide
if (buf_adr [i] == '@')
{
// allouer un buffer pour conserver la ligne
ligne_adr = malloc (taille + 2);
if (ligne_adr)
{
// mémoriser l'entrée du carnet d'adresse
memcpy (ligne_adr, buf_adr, taille + 1);
ligne_adr [taille + 1] = '\0';
adresse [nb_lignes ++] = ligne_adr;
}
else
// "Manque de place mémoire, l'application ne peut fonctionner"
errfatale ("MANQUE_MEMOIRE", NULL);
}
}
// terminé avec le fichier carnet d'adresse
fclose (fadr);
}
}
/* récupère le nom et l'adresse de l'expéditeur */
void lire_exped ()
{
char ficadr_exped [szchemin]; // fichier contenant l'adresse de l'expéditeur
FILE *fadr; // descripteur du fichier adresse de l'expéditeur
int i; // compteur
// détermine le nom du fichier contenant l'adresse de l'expéditeur
strcpy (ficadr_exped, direnv);
strcpy (ficadr_exped + strlen (direnv) - 6, ficdir ("FIC_ADR_EXPED"));
// ouvrir ce fichier en lecture
fadr = fopen (ficadr_exped, "r");
// initialisation du buffer de lecture
*buf_lect = '\0';
// si l'ouverture s'est bien passée
if (fadr)
{
// récupérer l'information
fgets (buf_lect, sz_buflect, fadr);
fclose (fadr);
}
// si on n'a pas récupéré d'adresse
if (! *buf_lect)
{
do
{
// demander à l'expéditeur de saisir ces informations
// "Nom, prénom et adresse Email de l'expéditeur :"
affiche_msg ("SAIS_FICADR");
fgets (buf_lect, sz_buflect, stdin);
// vérifier sommairement la présence de l'adresse email
i = 0;
while ((buf_lect [i] != '@') && buf_lect [i])
i++;
// nouvelle saisie si nécessaire
if (buf_lect [i] != '@')
// "Adresse Email manquante"
affiche_msg ("ADR_MANQUANTE");
}
while (buf_lect [i] != '@');
// et les mémoriser dans un fichier pour les fois suivantes
fadr = fopen (ficadr_exped, "w");
if (fadr)
{
fputs (buf_lect, fadr);
fclose (fadr);
}
}
// supprimer le '\n' dans la chaine lue
if (buf_lect [strlen (buf_lect) - 1] == '\n')
buf_lect [strlen (buf_lect) - 1] = '\0';
}
/* sélectionne des adresses de destinataires
en tenant compte de celles déjà utilisées */
void choixdest (char *motcle)
{
char buf_adr [szbufadr]; // buffer pour saisie adresse de destinataire
int car; // caractère lu au clavier
int i, j, erreurs; // compteurs
// initialisation
ajouts = 0;
// si le carnet contient des adresses
if (nb_lignes)
{
// aucun destinataire sélectionné
for (i = 0; i < nb_lignes; i++)
selection [i] = 0;
case HOME :
case HOMEg : monte (lignecour);
erreurs = 0;
break;
case FIN :
case FINg : descend (nb_lignes - lignecour - 1);
erreurs = 0;
break;
// sélectionner une adresse
case INSERT : selection [lignecour] = 1;
affligne (lignecour);
break;
// déselectionner une adresse
case SUPR : selection [lignecour] = 0;
affligne (lignecour);
break;
case ' ' : // sélectionner ou désélectionner une adresse
case '\n' : selection [lignecour] = 1 - selection[lignecour];
affligne (lignecour);
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"
// "Inser pour rajouter le destinataire courant"
// "Suppr pour le désélectionner"
// "Espace ou Entrée pour sélect / désélect."
// "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_CHOIX_ADR-4");
affiche_msg ("AIDE_CHOIX_ADR-5");
affiche_msg ("AIDE_CHOIX_ADR-6");
affiche_msg ("AIDE_CHOIX_ADR-7");
// variante pour la touche Esc
if (util_systemd ())
// "v ou Esc (2 fois) pour Valider la sélection\n"
affiche_msg ("AIDE_CHOIX_ADR-8b");
else
// "v ou Esc pour Valider la sélection\n"
affiche_msg ("AIDE_CHOIX_ADR-8");
// "Appuyer sur une touche pour continuer"
affiche_msg ("ATTENTE_CLAVIER");
leccar ();
// pas de break, on continue sur affpage
case CTRL : affpage ();
erreurs = 0;
case 'v' : // valider la sélection
case 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 != 'v' && car != ESC);
// On va recopier les adresses sélectionnées
// et les supprimer de la liste
j = 0;
for (i = 0; i < nb_lignes; i++)
{
// si adresse sélectionnée
if (selection [i])
{
// ajoute ce destinataire dans l'entête du fichier mail
ajout_adr (adresse [i], motcle);
// on peut libérer la mémoire occupée par l'adresse utilisée
free (adresse [i]);
}
// sinon, on la conserve
else
adresse [j++] = adresse [i];
}
// mise à jour du nombre d'adresses encore utilisables
nb_lignes = j;
// saisie manuelle d'autres descriptions d'utilisateurs
effpage ();
// "Vous pouvez préciser des destinataires inconnus dans le carnet d'adresse"
affiche_msg ("AIDE_CHOIX_ADR-9");
}
else
// "Carnet d'adresse vide, vous pouvez choisir d'autres destinataires"
affiche_msg ("AIDE_CHOIX_ADR-10");
// "Taper juste sur entrée quand il n'y en a plus"
affiche_msg ("AIDE_CHOIX_ADR-11");
// on repasse en mode saisie normale
mode_normal ();
do
{
// "Autre destinataire : "
affiche_msg_nocr ("AJOUT_DEST");
i = 0;
do
{
car = getchar ();
// on ne mémorise pas le passage à la ligne
if (car != '\n')
buf_adr [i++] = car;
}
while (car != '\n');
// on termine la chaine lue
buf_adr [i] = '\0';
// et si elle n'est pas vide, on mémorise le destinataire correspondant
if (*buf_adr)
ajout_adr (buf_adr, motcle);
}
while (*buf_adr);
// configurer la liaison clavier pour lecture directe avec timeout
mode_raw ();
// terminaison de la liste de destinataires de la catégorie traitée
// on ne génère pas de passage à la ligne si aucun
// destinataire n'a été sélectionné pour cette catégorie
if (ajouts)
fputc ('\n', fdest);
}
/* affiche une ligne de la liste des destinataires */
void affligne (int numlig)
{
int i; // simple compteur
i = 0;
// aller en début de ligne
putchar ('\r');
// si le destinataire de la ligne à afficher a été sélectionné
if (selection [numlig])
{
// passer en surbrillance
clair ();
// mettre aussi un > en début de ligne (pour les terminaux braille)
putchar ('>');
putchar (' ');
// afficher le destinataire
while (adresse [numlig][i] && i < colonpage - 2)
putchar (adresse [numlig][i++]);
// revenir en lunminosité normale
lumnor ();
}
// sinon
else
// afficher juste le destinataire
while (adresse [numlig][i] && i < colonpage)
putchar (adresse [numlig][i++]);
// aller en début de ligne
putchar ('\r');
}
/* ajoute un destinataire dans l'entête du fichier mail
on remet en forme les informations contenues dans la chaine destin
pour les présenter sous la forme : "description" <adresse>
seule l'adresse est conservée por les destinataires en copie cachée */
void ajout_adr (char *destin, char *motcle)
{
int debnom, finom, debadr, finadr; // position infos dans la chaine destin
char buf_adr [szbufadr]; // buffer pour mise en forme de l'adresse
int szbuf; // nombre de caractères mémorisés dans buf_adr
static int occupe; // nombre de caractères dans ligne courante du fichier
int i; // simple compteur (pour copie propre des données)
// on va chercher le début et la fin de l'adresse mail
finadr = strlen (destin) - 1;
// recherche de la fin de l'adresse email
while (finadr > 0 && (destin [finadr] == ' ' || destin [finadr] == '>'
|| destin [finadr] == '\t'))
finadr --;
// recherche du début de l'adresse email
debadr = finadr - 1;
// si la description du destinataire est présente
if (debnom < finom)
{
// la copier
buf_adr [szbuf++] = '"';
// l'utilisation de la variable i permet de ne pas
// modifier debnom qui pourtant ne resservira plus
for (i = debnom; i <= finom; i++)
buf_adr [szbuf++] = destin [i];