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
Bibliothèque de fonctions permettant de :
- mémoriser le mode d'encodage et le jeu de caractères du message
- convertir les accents et caractères spéciaux codés sur 7 bits
ou/et utilisant un jeu de caractères non ISO-8859 dans le message
- récupérer un nom de fichier joint
*/
/* mémorise dans encodage_texte la valeur
du champ Content-Transfer-Encoding */
void mem_encodage ()
{
int i; // numéro de caractère dans buf_lect
// se positionner après le nom de champ
i = 26;
// sauter les blancs
while (buf_lect [i] == ' ')
i++;
// détection de l'encodage (simplifiée, on analyse un ou deux caractère)
if (tolower (buf_lect [i]) == 'q')
encodage_texte = QuotedPrint;
// l'encodage peu fréquent "binary" ne doit pas être traité comme "base64"
else if (tolower (buf_lect [i]) == 'b' && tolower (buf_lect [i+1]) == 'a')
encodage_texte = Base64;
else
encodage_texte = xBits;
}
/* mémorise dans charset_texte le jeu de
caractères utilisé dans le texte du mail
retourne 1 si champ charset trouvé dans la ligne, 0 sinon */
int lire_charset ()
{
int i; // compteur
// initialisation
i = 1;
// chercher le mot charset dans la ligne et sortir s'il n'y est pas
while (tolower (buf_lect [i]) != 'c' || tolower (buf_lect [i+1]) != 'h')
if (! buf_lect [++i])
return (0);
// se positionner après le caractère =
while (buf_lect [i++] != '=')
if (! buf_lect [i])
return (0);
// sauter également les blancs s'il y en a
while (buf_lect [i] == ' ')
i++;
// sauter également le " s'il y est
if (buf_lect [i] == '"')
i++;
// détection du charset (simplifiée, on analyse un caractère)
if (tolower (buf_lect [i]) == 'i')
{
// jeu de caractère ISO
charset_texte = Iso8859;
// vérifier si variante Mac
while (tolower (buf_lect [i]) != 'x' || buf_lect [i+1] != '-'
|| tolower (buf_lect [i+2]) != 'm')
if (! buf_lect [++i])
return (1);
/* convertit la ligne lue en interprétant les caractères spéciaux */
void majligne ()
{
int i; // compteur
// suppression du . éventuel en première colonne
if (buf_lect [0] == '.')
{
i = 0;
do
buf_lect [i] = buf_lect [i + 1];
while (buf_lect [i++] != '\0');
}
// suppression de l'encodage quoted-printable
if (encodage_texte == QuotedPrint)
sup_quoted ();
// et de l'encodage base64
else if (encodage_texte == Base64)
{
i = decode64 (buf_lect);
// la génération d'un passage à la ligne jusqu'à la version
// 2.2.4 est supprimée : si elle suppléait à un bug, elle
// perturbait l'affichage des mails encodés base64.
// fin de ligne si le texte encodé base64 est terminé
if (i == 0)
*buf_lect = '\n';
}
// sinon, on rajoute juste un passage à la ligne
else
{
i = strlen (buf_lect);
buf_lect [i++] = '\n';
// terminaison de la chaine de caractères
buf_lect [i] = '\0';
}
// remplacement des caractère de controle
// dont certains déprogramment la visu
conv_carcontrole ();
// Dans les anciennes versions, on convertissait ici certaines séquences
// HTML qui NE DEVRAIT JAMAIS se trouver dans un TEXTE de mail correctement
// généré (mais on en trouve !!!!)
// Appel de l'instruction supprimé pour cohérence entre les options -h et -H
// conv_carhtm ();
// conversion des jeux de caractères non ISO
// traitement des jeux de caractères
// si mail encodé UTF-8
if (charset_texte == Utf8)
{
// et qu'on utilise le jeu de caractères ISO-8859
if (! util_utf8 ())
{
// conversion du jeu de caractères UTF8 en ISO-8859
conv_utf8_iso ();
// Normalement, le besoin de conversion des caractères
// Mac devrait être signalée dans le charset.
// Toutefois, il est préférable faire la conversion systématiquement
// Cette fonction remplace aussi le caractère A0 (hexa) par un blanc
conv_isomac ();
}
}
// sinon le mail est supposé encodé ISO-8859
else
{
// même raison de l'appel de cette fonction que précédemment
conv_isomac ();
// si on utilise le jeu de caractères UTF-8
if (util_utf8 ())
// conversion du jeu de caractères ISO-8859 en UTF8
conv_iso_utf8 (buf_lect); // fonction dans messages.c
}
}
/* suppression de l'encodage quoted-printable */
void sup_quoted ()
{
int carcode; // caractère correspondant à un codage quoted-printable
int i, j; // compteurs
// initialisation
i = 0;
j = 0;
// exploration de toute la ligne
while (buf_lect [i] != '\0')
{
// si caractère quoted printable à convertir
if (buf_lect [i] == '=' &&
((buf_lect [i+1] >= '0' && buf_lect [i+1] <= '9') ||
(buf_lect [i+1] >= 'A' && buf_lect [i+1] <= 'F') ||
(buf_lect [i+1] >= 'a' && buf_lect [i+1] <= 'f')))
// pour les maillers qui mettent les lettres hexa en minuscules !
{
// on décode le caractère correspondant
carcode = hexa (buf_lect + ++i);
// si ce n'est pas un caractère de controle ou si c'est un LF
if (carcode > 0x1F || carcode == '\n')
// le mémoriser
// Remarque : la conversion d'un LF peut être une source de
// problème d'affichage notamment avec vmailfic
buf_lect [j++] = carcode;
// sinon, si caractère de controle autre que CR
else if (carcode != '\r')
// mémoriser un blanc pour limiter les problèmes d'affichage
buf_lect [j++] = ' ';
// se positionner sur le caractère suivant
i = i + 2;
}
// sinon on conserve le caractère courant et on passe au suivant
else
buf_lect [j++] = buf_lect [i++];
}
// traitement de la fusion éventuelle de 2 lignes
if (buf_lect [i - 1] == '=')
j--;
else
buf_lect [j++] = '\n';
// terminaison de la chaine de caractères
buf_lect [j] = '\0';
}
/* conversion des caractères spéciaux sur Mac */
void conv_isomac ()
{
int i; // compteur
for (i = 0; buf_lect [i] != '\0'; i++)
{
switch (buf_lect [i])
{
case 0x92 :
case 0xB4 : buf_lect [i] = '\'';
break;
case 0x93 : buf_lect [i] = '«';
break;
case 0x94 : buf_lect [i] = '»';
break;
case 0x9C : buf_lect [i] = '½';
break;
case 0xA0 : buf_lect [i] = ' ';
default : break;
}
}
}
/* conversion du jeu de caractères UTF8 en ISO-8859 */
void conv_utf8_iso ()
{
/* indique que le caractère qui suit le à devra être converti
on utilise une variable statique pour garder l'info en mémoire dans le
cas où le à et le caractère qui suit seraient sur 2 lignes distinctes */
static int decalsuiv = 0;
/* idem si â , suivi du caractère 0x80, suivi d'un 3ème */
static int codespe = 0;
// tableau de conversion des caractères de la série E2809x
char E2809x [16] = {'-', '-', '-', '-', '-', '-', '|', '_',
'\'', '\'', ',', '`', '"', '"', '"', '"'};
int i, j; // compteurs
// initialisation
i = 0;
j = 0;
do
{
// si aucun traitement d'encodage sur 3 caractères en cours
if (!codespe)
{
switch (buf_lect [i])
{
// si caractère à , on convertira le caractère qui le suit
case 0xC3 : decalsuiv = 1;
case 0xC2 : break; // on saute le caractère  ou Ã
// si caractère Å suivi du caractère 93h
case 0xC5 : switch (buf_lect [i+1])
{
// on convertit le résultat en ¼
case 0x92 : buf_lect [j++] = 0xBC;
i++;
break;
// on convertit le résultat en ½
case 0x93 : buf_lect [j++] = 0xBD;
i++;
break;
// obligatoire pour éviter gros bug d'affichage!
// on convertit le résultat en s
case 0x9B : buf_lect [j++] = 's';
i++;
break;
default : buf_lect [j++] = buf_lect [i];
}
break;
// si caractère â , mémorisation encodage sur 3 caractères
case 0xE2 : codespe = 1;
break;
// pour tous les autres caractères, 2 cas possibles
default : if (decalsuiv)
{
// conversion du caractère qui suit le Ã
buf_lect [j++] = buf_lect [i] | 0x40;
decalsuiv = 0;
}
else
// ou simple copie du caractère courant
buf_lect [j++] = buf_lect [i];
}
}
// sinon, si on est sur le 2ème caractère d'un encodage sur 3 car
else if (codespe == 1)
{
// cas général (le 3ème caractère déterminera le résultat)
if (buf_lect [i] == 0x80)
codespe ++;
// cas particulier du symbole euro
else if (buf_lect [i] == 0x82 && buf_lect [i+1] == 0xAC)
{
buf_lect [j++] = 0xA4;
i++;
codespe = 0;
}
// encodage non reconnu
else
{
buf_lect [j++] = 0xE2;
buf_lect [j++] = buf_lect [i];
codespe = 0;
}
}
// traitement du dernier caractère d'un encodage sur 3 car
else if (codespe == 2)
{
if (0x90 <= buf_lect [i] && buf_lect [i] <= 0x9F)
buf_lect [j++] = E2809x [buf_lect [i] & 0x0F];
// on ne les met que si c'est possible sans
// écraser les caractères non encore traités
if (i > j)
buf_lect [j++] = '.';
if (i > j)
buf_lect [j++] = '.';
}
// sinon, cas d'une séquence encodée non répertoriée
else
{
if (i > j + 1)
{
// même précaution que pour pointillés
buf_lect [j++] = 0xE2;
buf_lect [j++] = 0x80;
}
buf_lect [j++] = buf_lect [i];
}
codespe = 0;
}
// si fin de ligne, on ne remet pas à jour decalsuiv et codespe
if (buf_lect [++i] == 0)
buf_lect [j++] = '\0';
}
while (buf_lect [i] != 0);
}
/* suppression des balises html et affichage du reste */
void supavantbody ()
{
static char *balise = "<body";
static int posbal = 0;
int poslig = 0;
int i = 0;
// tant que non fin de ligne et <body non trouvé
while (buf_lect [poslig] && avantbody)
{
// tant que le caractère courant en minuscules
// correspond à celui de la balise
while ((buf_lect [poslig] | 0x20) == balise [posbal])
{
// passer au caractère suivant des deux cotés
poslig ++;
posbal ++;
}
// si balise non trouvée
if (balise [posbal])
{
// si on est dans une autre balise
if (posbal)
// revenir au début de la balise à chercher
posbal = 0;
// sinon
else
// avancer d'un caractère dans la ligne
poslig ++;
}
// sinon
else
// balise trouvée
avantbody = 0;
}
// cas particulier : <body juste en fin de ligne
if (avantbody && (balise [posbal] == 0))
avantbody = 0;
// si balise non trouvée
if (avantbody)
// effacer la ligne
*buf_lect = '\0';
// sinon
else
{
// si balise entièrement dans la ligne
if (poslig > posbal)
{
// effacer dans la ligne tout ce qui précède cette balise
poslig = poslig - posbal;
i = 0;
do
buf_lect [i++] = buf_lect [poslig];
while (buf_lect [poslig++]);
}
// sinon si balise à cheval sur 2 lignes du code source
else if (poslig < posbal)
{
// chercher le décalage
i = posbal - poslig;
// aller en fin de ligne
while (buf_lect [poslig])
poslig ++;
// décaler la ligne de i caractères en remontant depuis la fin
i = i + poslig;
while (poslig)
buf_lect [i --] = buf_lect [poslig --];
// recopier le début de la balise
do
buf_lect [i] = balise [i];
while (i --);
}
// réinitialiser posbal pour nouvelle recherche dans vmailfic
posbal = 0;
}
}
/* supprimer les balises HTML et leur contenu */
void sup_balhtm ()
{
static int dansbal = 0;
int i, j;
// initialisation
i = 0;
j = 0;
// pour chaque caractère de la ligne
while (buf_lect [i])
{
// si caractère <
if (buf_lect [i] == '<')
{
// on rentre dans une balise HTML
dansbal = 1;
// si la balise '<' est précédée de blancs
if (j > 0 && buf_lect [j - 1] == ' ')
{
// les supprimer
do
j--;
while (buf_lect [j] == ' ' && j > 0);
// sauf un s'il n'est pas en début de ligne
if (buf_lect [j] != ' ')
j++;
}
}
// si on n'est pas dans un balise HTML
if (! dansbal)
// on affichera le caractère courant
buf_lect [j++] = buf_lect [i];
// si caractère >
if (buf_lect [i] == '>')
// on sort d'une balise HTML
dansbal = 0;
// passer au caractère suivant
i++;
}
// terminer la ligne si nécessaire
buf_lect [j] = '\0';
}
/* réduit à un les espaces multiples dans un texte htlm */
void sup_multiblancs ()
{
int i, j;
// initialisation
i = 0;
j = 0;
// pour chaque caractère de la ligne
while (buf_lect [i])
{
// conserver ce caractère
buf_lect [j++] = buf_lect [i];
// si c'est un espace
if (buf_lect [i] == ' ')
{
// sauter les espaces qui le suivent
do
i++;
while (buf_lect [i] == ' ');
}
// sinon passer au caractère suivant
else
i++;
}
// supprimer les blancs en fin de ligne
while (j && buf_lect [j] == ' ')
j--;
// terminer la ligne si nécessaire
buf_lect [j] = '\0';
}
/* convertir les caractères HTML, par exemple les ’ en apostrophes */
void conv_carhtm ()
{
// caractères de la forme &#nombre; (avec un nombre > à 255)
int valeurcar [] = {339, 8211, 8216, 8217, 0}; // valeur du caractère
char carequiv [] = "½-''"; // caractère équivalent
// caractères symbolisés par une chaine commençant par & et finissant par ;
char *carnomme [] = {" nbsp", "<lt", ">gt", "&", "'quot", "'rsquo",
"'apos", "¤euro", "àagrave", "âacirc", "çccedil",
"éeacute", "èegrave", "êecirc", "îicirc", "ôocirc",
"ùugrave", "ûucirc", "°deg", NULL};
char cartrouve; // caractère trouvé à partir de carnomme
int trouve; // indique si on a trouvé un caractère nommé
int choix; // numéro du caractère nommé en cours de test
int val; // valeur numérique après &#
int depl; // numéro du caractère nommé testé
int i, j; // position dans buf_lect en lecture et en écriture
// initialisation
i = 0;
j = 0;
do
{
// si on trouve les caractères & et on traite tous les caractère nommés
// ou si on trouve les caractères &# à la suite
if (buf_lect [i] == '&')
{
// si ce qui suit risque d'être le codage d'un nombre
if (buf_lect [i+1] == '#')
{
depl = 2;
val = 0;
// extraire ce nombre
while (buf_lect [i + depl] >= '0' && buf_lect [i + depl] <= '9')
val = (val * 10) + (buf_lect [i + depl++] & 0x0F);
// si on est bien tombé sur un nombre
if (buf_lect [i + depl] == ';')
{
// et que ce nombre tient sur un octet
if (val <= 255)
{
// prendre en compte le caractère équivalent
buf_lect [j++] = val;
// et sauter la taille de la chaine analysée
i = i + depl;
}
// sinon
else
{
choix = 0;
// chercher si le nombre estmémorise dans valeurcar
while (valeurcar [choix] && val != valeurcar [choix])
choix ++;
// s'il l'est
if (valeurcar [choix])
{
// récupérer le caractère équivalent
buf_lect [j++] = carequiv [choix];
// et sauter la taille de la chaine analysée
i = i + depl;
}
// sinon
else
// simple copie du caractère courant
buf_lect [j++] = '&';
}
}
// sinon
else
// simple copie du caractère courant
buf_lect [j++] = '&';
}
// sinon, caractère nommé
else
{
// initialisation
trouve = 0;
choix = 0;
// chercher un éventuel caractère nommé
while (!trouve && carnomme [choix])
{
// on vérifie caractère par caractère
depl = 1;
while ((buf_lect [i+depl] | 0x20) == carnomme [choix][depl])
depl ++;
// si caractère nommé trouvé
if (buf_lect [i + depl] == ';' && !carnomme [choix][depl])
// mémoriser cette information
trouve = 1;
else
// sinon, essayer avec le caractère nommé suivant
choix ++;
}
// si caractère nommé trouvé
if (trouve)
{
// sélectionner le caractère trouvé
cartrouve = carnomme [choix][0];
// si on trouvé un caractère ASCII ou on
// travaille avec un jeu de caractères ISO
if ((cartrouve & 0x80) == 0 || ! util_utf8 ())
{
// remplacer le code ½par le caractère adéquat
buf_lect [j++] = cartrouve;
}
// sinon (on est en UTF-8) si caractère euro
else if (cartrouve == 0xA4)
{
// générer la séquence UTF-8 adéquate
buf_lect [j++] = 0xE2;
buf_lect [j++] = 0x82;
buf_lect [j++] = 0xAC;
}
// sinon (autre caractère UTF-8 plus facile à générer)
else
{
// générer la séquence UTF-8 adéquate
buf_lect [j++] = 0xC3;
buf_lect [j++] = cartrouve - 0x40;
}
// et sauter la taille du caractère nommé
i = i + depl;
}
// sinon
else
// simple copie du caractère courant
buf_lect [j++] = '&';
}
}
// sinon
else
// simple copie du caractère courant
buf_lect [j++] = buf_lect [i];
}
// on fait ce traitement jusqu'à la fin de la ligne
while (buf_lect [i++] != 0);
}
/* convertir les caractères de controle de la ligne */
void conv_carcontrole ()
{
int i, j; // numéros de caractère dans buf_lect
// initialisation
i = 0;
j = 0;
// calculer la taille de la ligne après traitement
while (buf_lect [i])
{
// si caractère de controle autre que \n ou \r suivi de \n
if (buf_lect [i] < ' ' && buf_lect [i] != '\n')
if (buf_lect [i] != '\r' || buf_lect [i+1] != '\n')
// on le convertira
j++;
// prise en compte du caractère traité et passage au suivant
i++;
j++;
}
// pour éviter un débordement de tableau si ligne très longue
if (j >= sz_buflect)
j = sz_buflect - 1;
// si des caractères de controle ont été trouvés
if (i != j)
{
// recopie du caractère de fin de chaine
buf_lect [j--] = '\0';
i--;
// conversion de la ligne de la fin au début
// pour éviter des écrasements de caractères
while (i < j)
{
// si caractère de controle à convertir
if (buf_lect [i] < ' ' && buf_lect [i] != '\n')
{
if (buf_lect [i] != '\r' || buf_lect [i+1] != '\n')
{
// on en met deux à la place
buf_lect [j--] = buf_lect [i--] | 0x40;
buf_lect [j--] = '^';
}
else
// sinon, simple déplacement du caractère
buf_lect [j--] = buf_lect [i--];
}
else
// sinon, simple déplacement du caractère
buf_lect [j--] = buf_lect [i--];
}
}
}
/* retourne la position d'un nom de fichier joint dans la ligne courante */
int posnomfic ()
{
char chaineref [] = "name="; // chaine à chercher pour trouver fichier joint
int i, j; // compteurs
if (strlen (buf_lect) < 7)
// la ligne est trop courte pour contenir un nom de fichier joint
return (0);
// le mot clé name ou filename ne commence pas en première colonne
i = 1;
// recherche de la chaine name =
do
{
// test sur le premier caractère
if (tolower (buf_lect [i]) == *chaineref)
{
// et les suivants
j = 1;
while (tolower (buf_lect [i+j]) == chaineref [j])
j++;
// trouvé ?
if (chaineref [j] == '\0')
{
// sauter le " éventuel
if (buf_lect [i+j] == '"')
i++;
// et retourner la position du nom
return (i + j);
}
}
}
// continuer la recherche
while (buf_lect [++i] != '\0');