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 prépare une réponse pour le fichier mail passé en paramètre
Le chemin d'accès au fichier peut être absolu ou relatif.
A partir du squelette généré, la réponse se fait grace à l'éditeur vi
Le fichier obtenu est ensuite stoqué dans le répertoire des mails à envoyer
Pour que cela soit possible, il faut :
- soit que la commande repmail soit lancée depuis la chaine vmail...
- soit préciser le nom du répertoire de l'arborescence des mails
*/
#define appli // pour la déclaration de variables globales à l'application
/* variable globale au source
(pour éviter des passages de paramètres) */
long numail; // numéro que prendra le mail généré
// caractère signifcatif de la variable d'environnement libremail_xorig
char xorig;
/* programme principal */
int main (int nbarg, char *varg[])
{
char ficmail [szchemin]; // fichier mail de réponse
char fentete [szchemin]; // fichier contenant l'entete du message
char commande [szchemin]; // commande d'appel de l'éditeur
char *editeur; // éditeur utilisé pour saisir la réponse
char *varenv_xorig; // variable d'environnement libremail_xorig
// récupération du nom de l'exécutable
memcom (*varg);
// si nombre d'arguments correct
if (--nbarg == 1 || nbarg == 2)
{
// ouvrir le fichier mail auquel on doit répondre
fmail = fopen (varg [1], "r");
// terminé si le fichier n'a pas pu être ouvert
if (! fmail)
{
if (access (varg [1], 0) == 0)
// "Problème d'accès au fichier %s"
errfatale ("ACCES_FICHIER", varg [1]);
else
// "Fichier %s inexistant"
errfatale ("FICH_INEXISTANT", varg [1]);
}
}
// sinon, rappel de la syntaxe de la commande
else
// "Syntaxe : %s nom_fichier_mail [répertoire_emails]"
psyntaxe ("SYNT_REP/TRSF-MAIL");
// 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';
// passer en mode standard pour les lectures au clavier
mode_normal ();
// récupérer le nom du répertoire des mails à envoyer
recupdirenv (nbarg, varg [2]);
// créer un nom de fichier temporaire pour l'entête du mail
// il a toujours le même nom pour éviter de polluer le
// répertoire d'envoi en cas de fausse manoeuvre opérateur (^C)
sprintf (fentete, "%s/tmp-ent", direnv);
// fabriquer l'entête du mail de réponse
gene_entete (fentete);
// créer un nom de fichier temporaire pour le message
sprintf (ficmail, "%s/tmp-mes", direnv);
// fabriquer le message de réponse
gene_enteterep (ficmail);
// Choix de l'éditeur de textes
editeur = getenv ("EDITOR");
if (! editeur)
editeur = "vi";
// c'est au tour de l'utilisateur de répondre au mail
sprintf (commande, "%s %s", editeur, ficmail);
system (commande);
// mémoriser les dates et heure d'envoi du message
ajout_date (fentete);
// on va regrouper l'entête et le message dans un fichier numéroté définitif
fusionner (fentete, numail, ficmail);
// mettre à jour le fichier numail du répertoire de sortie
sauv_num_dermail (direnv, numail);
// ajouter la signature au message, si elle existe
ajout_sign (ficmail);
// modification avant envoi ?
// "Voulez vous modifier le fichier complet avant envoi ? "
affiche_msg_nocr ("MAJ_MAIL_PRET");
if (tolower (getchar ()) != 'n')
{
// si oui, appeler l'éditeur
sprintf (commande, "%s %s", editeur, ficmail);
system (commande);
}
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* lit l'entête du message choisi et fabrique celle de la réponse */
void gene_entete (char *nomfic)
{
long pos_deblig; // position dans le fichier en début de ligne courante
// position dans le fichier des champs pouvant tenir sur plusieurs lignes
long posTo = -1, posCc = -1, posSubject = -1, posRef = -1;
// mémorisation directe d'autres champs
// grosse taille des buffers pour ne pas tronquer une adresse
// de type confirmation d'inscription à une mailing list
char bufFrom [szbuf], bufXorig [szbuf], bufReply [szbuf], bufMesid [szbuf];
char *bufexped; // pour traitement commun de bufFrom et bufXorig;
char reponse [10]; // réponse à une question
int choix, choixmax; // choix des destinataires
int i, j; // compteurs
// fabriquer et ouvrir en écriture le fichier d'entête
fdest = fopen (nomfic, "w");
if (! fdest)
// "Impossible de créer un fichier d'entête %s"
errfatale ("IMPOS_CRE_ENTETE", nomfic);
// lecture et mémorisation de l'entête du message
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 ();
// pour éviter un débordement de buffer lors d'une copie
buf_lect [szbuf - 1] = '\0';
// repérage des champs importants et mémorisation
// de leur contenu ou de leur position
if (start ("From") || (start ("X-Original-From") && xorig != 'n'))
{
// initialiser bufexped avec bufFrom ou bufXorig
if (toupper (*buf_lect) == 'F')
bufexped = bufFrom;
else
bufexped = bufXorig;
// convertir les caractères spéciaux éventuels
majlignentete ();
// analyse et copie dans le bufFrom
// on n'utilise pas memconvbuf parce qu'il tronque à 80 caractères
i = 0;
j = 0;
do
{
// recopier un caractère
bufexped [i] = buf_lect [i];
// mémoriser la présence d'une adresse Email dans la ligne
if (buf_lect [i] == '@')
j = i;
}
while (buf_lect [i++]);
// si aucune adresse email valide n'a été trouvée dans la ligne
if (buf_lect [j] != '@')
{
// lire la ligne suivante
lire_fmail ();
// convertir les caractères spéciaux éventuels
majlignentete ();
// et copie dans le buffer à la suite de la ligne précédente
j = 0;
i --;
while (buf_lect [j] && i < szbuf - 1)
{
// recopier un caractère et passer au suivant
bufexped [i++] = buf_lect [j++];
}
// terminer la chaine de caractères
bufexped [i] = '\0';
}
}
else if (start ("To"))
posTo = pos_deblig; // on mémorise la position de la ligne
else if (start ("Cc"))
posCc = pos_deblig; // on mémorise la position de la ligne
else if (start ("Reply-To"))
{
// pas de conversion des lignes contenant une adresse Email
// (on évite ainsi de supprimer les _ de certaines adresses)
strcpy (bufReply, buf_lect);
}
else if (start ("Subject"))
posSubject = pos_deblig; // on mémorise la position de la ligne
else if (start ("Message-Id"))
{
// on récupère juste la valeur du Message-Id sans conversion
// elle servira à générer les champs In-Reply-To et Reference
if (buf_lect [11] == ' ')
strcpy (bufMesid, buf_lect + 12);
else
strcpy (bufMesid, buf_lect + 11);
}
else if (start ("Reference"))
posRef = pos_deblig; // on mémorise la position de la ligne
}
while (buf_lect [0] != '\0'); // lecture entête terminée si ligne vide
// récupérer l'adresse de celui qui répond au mail
lire_exped ();
// chercher le numéro du mail que l'on va créer
numail = num_dermail (direnv) + 1;
// génération du champ Message-Id
gen_mes_id (fdest, numail, buf_lect);
// choix des destinataires
// pas de sélection manuelle des adresses, mais jusqu'à 6 choix
// en fonction des caractéristiques du mail auquel on répond
// "\nRépondre à :\n"
affiche_msg ("CHOIX_REP-0");
// si le champ X-Original_From est présent dans le mail
if (*bufXorig)
{
// "1) Le vrai expéditeur :%s\n\n"
// "2) Le vrai expéditeur + celui qui répond en copie : %s\n\n"
// "3) Le vrai expéditeur + destinataires en copie à choisir\n"
printf (message ("CHOIX_REP-1A"), bufXorig + 16);
printf (message ("CHOIX_REP-2A"), buf_lect);
affiche_msg ("CHOIX_REP-3A");
}
// sinon (le champ From contient l'expéditeur)
else
{
// "1) L'expéditeur :%s\n\n"
// "2) L'expéditeur + celui qui répond en copie : %s\n\n"
// "3) L'expéditeur + destinataires en copie à choisir\n"
printf (message ("CHOIX_REP-1"), bufFrom + 5);
printf (message ("CHOIX_REP-2"), buf_lect);
affiche_msg ("CHOIX_REP-3");
}
// cette liste peut tenir sur plusieurs lignes
aff_debliste (posTo);
putchar ('\n');
// 2 libellés également pour le choix 5
if (*bufXorig)
// "5) Le vrai expéditeur + destinataire(s) principal/aux"
affiche_msg ("CHOIX_REP-5A");
else
// "5) L'expéditeur + destinataire(s) principal/aux"
affiche_msg ("CHOIX_REP-5");
// ces choix ne sont rajoutés que s'ils sont possibles
if (*bufReply)
{
// "6) A l'adresse pour répondre :%s\n"
// "7) A l'adresse pour répondre + celui qui répond en copie\n\n"
putchar ('\n');
printf (message ("CHOIX_REP-6"), bufReply + 9);
putchar ('\n');
affiche_msg ("CHOIX_REP-7");
choixmax = 7;
}
else
choixmax = 5;
if (*bufXorig)
{
// "8) L'expéditeur falsifié :%s\n\n"
// "9) L'expéditeur falsifié + destinataires en copie à choisir\n"
printf (message ("CHOIX_REP-8"), bufFrom + 5);
affiche_msg ("CHOIX_REP-9");
choixmax = 9;
}
// génération de la liste des destinataires principaux
// (sauf pour le choix 4)
switch (choix)
{
case 1 :
case 2 :
case 3 :
case 5 : // expéditeur ou vrai expéditeur
if (*bufXorig)
fprintf (fdest, "To:%s", bufXorig + 16);
else
fprintf (fdest, "To:%s", bufFrom + 5);
// terminer la ligne pour les choix 1 à 3
if (choix != 5)
fputc ('\n', fdest);
break;
case 6 :
case 7 : // adresse pour répondre
fprintf (fdest, "To:%s\n", bufReply + 9);
break;
case 8 :
case 9 : // expéditeur falsifié
fprintf (fdest, "To:%s\n", bufFrom + 5);
break;
}
// génération de la liste des destinataires en copie
// (ou destinataire principaux pour choix 4 et 5)
switch (choix)
{
case 2 :
case 7 : // celui qui répond en copie
lire_exped ();
ajouts = 0;
ajout_adr (buf_lect, "Cc");
fputc ('\n', fdest);
break;
case 3 :
case 9 : // destinataires en copie à choisir
// charger le carnet d'adresses
charge_carnet_adr ();
// configurer la liaison clavier
// pour lecture directe avec timeout
mode_raw ();
// et choisir des destinataires
choixdest ("Cc");
// on repasse en mode saisie normale
mode_normal ();
break;
case 4 :
case 5 : // destinataires principaux
// se positionner sur le champ à copier
fseek (fmail, posTo, SEEK_SET);
// lire et copier la première ligne
lire_fmail ();
// en tenant compte éventuellement de la ligne précédente
if (choix == 4)
fputs (buf_lect, fdest);
else
fprintf (fdest, ",\n\t%s", buf_lect + 4);
// tester la ligne suivante
lire_fmail ();
// recopier jusqu'à la fin de la liste
while (*buf_lect == ' ' || *buf_lect == '\t')
{
fprintf (fdest, "\n%s", buf_lect);
lire_fmail ();
}
// terminer proprement la liste des destinataires
fputc ('\n', fdest);
// rajout à la demande des destinataires en copie
// à la suite de la liste des destinataires principaux
if (posCc >= 0 && (choix == 4 || choix == 5))
{
// "\nDestinataires en copie :"
affiche_msg ("AJOUT_DESTCOP-1");
aff_debliste (posCc);
// traitement réponse valable en de nombreuses langues
// si la réponse ne commence pas par 'n', c'est oui
// (ceux qui obligent à répondre 'y' sont de gros nuls)
if (tolower (*reponse) != 'n')
{
// se positionner sur le champ à copier
fseek (fmail, posCc, SEEK_SET);
// lire la première ligne
lire_fmail ();
// copier jusqu'à la fin de la liste
do
{
fprintf (fdest, "%s\n", buf_lect);
lire_fmail ();
}
while (*buf_lect == ' ' || *buf_lect == '\t');
}
}
break;
}
// génération du champ Subject
if (posSubject >= 0)
{
// lire la ligne contenant le sujet
fseek (fmail, posSubject, SEEK_SET);
lire_fmail ();
// convertir les caractères spéciaux éventuels
// c'est dans envmail qu'on réencodera éventuellement ce champ
majlignentete ();
// si la ligne du sujet n'est pas vide
if (strlen (buf_lect) > 9)
{
// si le sujet du mail commence par les lettres re
if (tolower (buf_lect [9]) == 'r' && tolower (buf_lect [10]) == 'e')
{
// si le sujet commence par Re: , RE: , re: etc...
if (buf_lect [11] == ':')
// On utilise la syntaxe la plus courante Re:
fprintf (fdest, "Subject: Re:%s", buf_lect + 12);
// sinon si le sujet commence par Re : , RE : , re : etc...
else if (buf_lect [11] == ' ' && buf_lect [12] == ':')
// on supprime le blanc avant le :
fprintf (fdest, "Subject: Re:%s", buf_lect + 13);
// sinon (les lettres re ne sont pas suivies d'un :
else
// on rajoute un Re: en début de sujet
fprintf (fdest, "Subject: Re: %s", buf_lect + 9);
}
// sinon
else
// on rajoute un Re: en début de sujet
fprintf (fdest, "Subject: Re: %s", buf_lect + 9);
// lire la ligne suivante
lire_fmail ();
}
else
{
// on va vérifier si le sujet est sur la ligne suivante
lire_fmail ();
// le libellé du sujet dépendra du résultat du test
if (*buf_lect == ' ' || *buf_lect == '\t')
fputs ("Subject: Re: ", fdest);
else
{
// "Subject: Réponse à message sans objet précisé"
fputs (message ("SUJET_VIDE"), fdest);
}
}
// tantque c'est aussi une ligne du sujet
while (*buf_lect == ' ' || *buf_lect == '\t')
{
// convertir les caractères spéciaux éventuels
majlignentete ();
// rajouter le contenu de la ligne au sujet
fputs (buf_lect + 1, fdest);
// et lire la ligne suivante
lire_fmail ();
}
// terminer la ligne contenant le sujet
fputc ('\n', fdest);
}
else
{
// "Subject: Réponse à message sans objet précisé"
fputs (message ("SUJET_VIDE"), fdest);
fputc ('\n', fdest);
}
// si le mail auquel on répond avait un identificateur
if (*bufMesid)
{
// on va générer le champ Reference
// s'il y avait déjà un champ Reference
if (posRef >= 0)
{
// se positionner sur ce champ
fseek (fmail, posRef, SEEK_SET);
// lire la première ligne
lire_fmail ();
// copier jusqu'à la fin de la liste
do
{
fprintf (fdest, "%s\n", buf_lect);
lire_fmail ();
}
while (*buf_lect == ' ' || *buf_lect == '\t');
// rajouter la dernière référence
fprintf (fdest, " %s\n", bufMesid);
}
// sinon
else
// créer un champ référence
fprintf (fdest, "Reference: %s\n", bufMesid);
// variante (qui suppose des conversions avant envoi du mail)
// fprintf (fdest, "Content-Transfer-Encoding: quoted-printable\n");
// un copyright qui n'est pas celui d'Outlook ;-))
// "libremail : logiciel libre multilingue"
fprintf (fdest, "User-Agent: libremail : %s\n",
message ("QUALIF_LIBREMAIL"));
// permettra de relire ce fichier
fclose (fdest);
}
/* lit le message choisi et fabrique le squelette de la réponse
cette fonction traite essentiellement l'entête du mail
puis appelle gene_mesrep pour le rajout du corps du mail */
void gene_enteterep (char *nomfic)
{
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, posUseAgent;
// fabriquer et ouvrir en écriture le fichier mail
fdest = fopen (nomfic, "w");
if (! fdest)
// "Impossible de créer le fichier mail %s"
errfatale ("IMPOS_CRE_FICMAIL", nomfic);
// on revient au début du fichier mail
rewind (fmail);
// 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"))
posUseAgent = pos_deblig;
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
// sauter des lignes pour réponse avant le message
fputc ('\n', fdest);
fputc ('\n', fdest);
// rappel des caractéristiques du message auquel on répond
if (posUseAgent >= 0)
copchamp (posUseAgent, 0);
if (posDate >= 0)
copchamp (posDate, 0);
if (posFrom >= 0 && (posXorig < 0 || xorig == '2'))
copchamp (posFrom, 1);
if (posXorig >= 0)
copchamp (posXorig, 1);
if (posTo >= 0)
copchamp (posTo, 1);
if (posCc >= 0)
copchamp (posCc, 1);
if (posReply >= 0)
copchamp (posReply, 1);
if (posSubject >= 0)
copchamp (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);
lire_fmail ();
// copie du contenu du mail
if (ctypeorig & Multipart)
// il faudra analyser les sections
gene_mesrep ();
else
// une simple copie du texte suffit
copie_texte ();
// 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 du mail
if (multipalter)
posit_texte ();
// générer une ligne de séparation avec l'entête
genligne ("\n");
// si structure du mail non conforme, message d'erreur
if (! lire_fmail ())
// "Pas de zone texte dans ce mail !!!"
genligne (message ("MANQUE_ZONE_TEXTE"));
// lecture et mémorisation du corps du message
do
{
// mise en forme et mémorisation de la dernière ligne lue
majligne ();
// 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 ())
{
do
lire_fmail ();
while (*buf_lect);
}
}
// on s'arrête en fin de fichier, ou sur la prochaine bordure
while (nbordures == 0 || ! surbordure ());
// si mode multipart mixed on va lister les pièces jointes
if (ctypeorig == MultipMixed)
liste_pj ();
}
/* lecture et copie d'un mail de type text/plain */
void copie_texte ()
{
// si texte encodé base 64
if (encodage_texte == Base64)
// générer une ligne de séparation avec l'entête
genligne ("\n");
// répéter
do
{
// mise en forme de la dernière ligne lue
majligne ();
// mémorisation de cette ligne
if (buf_lect [strlen (buf_lect) - 1] != '\n')
regroupeligne (buf_lect);
else
genligne (buf_lect);
// et lecture de la suivante
}
// on s'arrête en fin de fichier
while (lire_fmail ());
}
/* mémorise une ligne du mail */
void genligne (char *buffer)
{
char * nouvligne;
int taille_ligne;
int i;
// récupérer la longueur de la ligne
taille_ligne = strlen (buffer);
// si ligne longue
if (taille_ligne > 80)
{
// on tente de la tronquer à moins de 80 car
i = 70;
// chercher un blanc pour passer à la ligne
// ou un \n résultant d'un abus de l'encodage Mime
while (i > 0 && buffer [i] != ' ' && buffer [i] != '\n')
i--;
// si pas de blanc trouvé
if (i == 0)
{
// on en cherche un dans l'autre sens
i = 70;
while (i < taille_ligne && buffer [i] != ' ' && buffer [i] != '\n')
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;
// recopier les données dans ce tableau
fputc ('>', fdest);
if (taille_ligne > 1)
fputc (' ', fdest);
for (i = 0; i < taille_ligne; i++)
fputc (buffer [i], fdest);
// si la ligne a été tronquée
if (taille_ligne < strlen (buffer))
{
// générer un passage à la ligne
fputc ('\n', fdest);
// et traiter la suite
genligne (buffer + taille_ligne + 1);
}
}