/*
Fichier trtentete.c
Auteur Bernard Chardonneau
Logiciel libre, droits d'utilisation précisés en français
dans le fichier : licence.fr
Traductions des droits d'utilisation dans les fichiers :
licence.de , licence.en , licence.es , licence.it
licence.nl , licence.pt , licence.eo , licence.eo-utf
Bibliothèque de fonctions permettant de
- repérer les champs de l'entête du mail
- convertir dans ces champs les accents et caractères spéciaux
codés sur 7 bits grace à l'encodage quoted-printable
- mémoriser les lignes de l'entête après conversion
*/
#include <stdio.h>
#include "buflect.h"
#include "encodage.h"
#include "trtentete.h"
/* cherche si la dernière ligne lue commence par un mot clé particulier */
int start (char *motcle)
{
int i;
i = 0;
// on teste caractère par caractère en ignorant la casse
while (motcle [i] && tolower (buf_lect [i]) == tolower (motcle [i]))
i++;
// le mot clé doit être suivi de : dans la ligne lue
return (buf_lect [i] == ':');
}
/* convertit la ligne d'entête en interprétant les caractères spéciaux */
void majlignentete ()
{
int encodage; // mode d'encodage
int charset; // jeu de caractères
int carcode; // caractère correspondant à un codage quoted-printable
int decalsuiv; // indicateur pour conversion de caractère encodé Utf8
int decode_; // indicateur pour conversion '_' en ' '
char carcourant; // caractère contenant une valeur en base64
int valcar [4]; // valeur après conversion des caractères encodés base64
int i, j, k, l; // compteurs
// initialisation
i = 0;
j = 0;
encodage = defaut;
charset = defaut;
decode_ = 1;
// exploration de toute la ligne
while (buf_lect [i] != '\0')
{
// si début de mot d'encodage
if (buf_lect [i] == '=' && buf_lect [i+1] == '?' && encodage == defaut)
{
// se positionner sur le charset
i = i + 2;
// identification simplifiée du charset (sur 1 caractère)
if (tolower (buf_lect [i]) == 'i')
charset = Iso8859;
else if (tolower (buf_lect [i]) == 'u')
{
charset = Utf8;
decalsuiv = 0; // initialisation indicateur de conversion
}
else
charset = xCharset; // sera traité comme ISO-8859
// aller à la fin du charset
do
i++;
while (buf_lect [i] && buf_lect [i] != '?');
// se positionner sur le caractère d'encodage
i++;
// identification du mode d'encodage
if (tolower (buf_lect [i]) == 'q')
encodage = QuotedPrint;
else if (tolower (buf_lect [i]) == 'b')
encodage = Base64;
else
encodage = xBits;
// aller au début de la zone encodée
i = i + 2;
}
// si fin de zone encodée
if (buf_lect [i] == '?' && buf_lect [i+1] == '=' && encodage != defaut)
{
// sauter le marqueur de fin
i = i + 2;
// réinitialiser les indicateurs d'état
charset = defaut;
encodage = defaut;
}
// sinon si encodage quoted printable en cours
else if (buf_lect [i] == '=' && encodage == QuotedPrint
&& ((buf_lect [i+1] >= '0' && buf_lect [i+1] <= '9')
|| (buf_lect [i+1] >= 'A' && buf_lect [i+1] <= 'F')))
{
// on récupère le caractère correspondant
carcode = hexa (buf_lect + ++i);
// si jeu de caractères ISO-8859 dans la ligne d'entête
if (charset != Utf8)
{
// si le caractère est un caractère de controle
if (carcode < 0x20)
{
// et que c'est un caractère autre que CR
if (carcode != '\r')
// le remplacer par un blanc pour
// limiter les problèmes d'affichage
buf_lect [j++] = ' ';
}
// sinon si c'est un caractère accentué
// et que l'on fait un affichage UTF-8
else if ((carcode & 0x80) && util_utf8 ())
{
// si caractère entre 0xC0 et 0xFF
if (carcode & 0x40)
{
// mémoriser le caractère converti en UTF-8
buf_lect [j++] = 0xC3;
buf_lect [j++] = carcode - 0x40;
}
// sinon (caractère entre 0x80 et 0xFF)
else
{
// mémoriser le caractère converti en UTF-8
buf_lect [j++] = 0xC2;
buf_lect [j++] = carcode;
}
}
// sinon (cas général)
else
// mémoriser le caractère sans conversion
buf_lect [j++] = carcode;
}
// sinon, jeu de caractères UTF-8
else
{
// si on affiche les caractères en UTF-8
if (util_utf8 ())
// mémoriser le caractère sans conversion
buf_lect [j++] = carcode;
// sinon si caractère à on convertira le caractère qui suit
else if (carcode == 0xC3)
decalsuiv = 1;
// on recopie les caractères autres que  et CR
else if (carcode != 0xC2 && carcode != '\r')
{
if (decalsuiv)
{
// en faisant une conversion si nécessaire
carcode = carcode | 0x40;
decalsuiv = 0;
}
buf_lect [j++] = carcode;
}
}
// se positionner sur le caractère suivant
i = i + 2;
}
// sinon si encodage base64 en cours
else if (encodage == Base64)
{
// décoder une série de 4 caractères
for (k = 0; k < 4; k++)
{
// récupérer un caractère
carcourant = buf_lect [i++];
// chercher sa valeur sur 6 bits et la mémoriser
if ('A' <= carcourant && carcourant <= 'Z')
valcar [k] = carcourant - 'A';
else if ('a' <= carcourant && carcourant <= 'z')
valcar [k] = carcourant + 26 - 'a';
else if ('0' <= carcourant && carcourant <= '9')
valcar [k] = carcourant + 52 - '0';
else if (carcourant == '+')
valcar [k] = 62;
else if (carcourant == '/')
valcar [k] = 63;
}
// reconstituer les 3 caractères décodés correspondants
k = 0;
valcar [k++] = (valcar [0] << 2) | (valcar [1] >> 4);
// s'il y avait un = , ça faisait moins de 3 caractères à obtenir
if (buf_lect [i-2] != '=')
{
valcar [k++] = (valcar [1] << 4) | (valcar [2] >> 2);
if (carcourant != '=')
valcar [k++] = (valcar [2] << 6) | (valcar [3]);
}
// si jeu de caractères ISO-8859 et on fait un affichage UTF-8
if (charset != Utf8 && util_utf8 ())
{
// convertir caractères de ISO-8859 en UTF-8 et les mémoriser
// le test j < i permet d'éviter d'écraser la chaine initiale
for (l= 0; l < k && j < i; l++)
{
// si le caractère est un caractère de controle
if (valcar [l] < 0x20)
{
// et que c'est un caractère autre que CR
if (valcar [l] != '\r')
// le remplacer par un blanc pour
// limiter les problèmes d'affichage
buf_lect [j++] = ' ';
}
// sinon si caractère spécial
else if (valcar [l] & 0x80)
{
// si caractère entre 0xC0 et 0xFF
if (valcar [l] & 0x40)
{
// mémoriser le caractère converti en UTF-8
buf_lect [j++] = 0xC3;
buf_lect [j++] = valcar [l] - 0x40;
}
// sinon (caractère entre 0x80 et 0xFF)
else
{
// mémoriser le caractère converti en UTF-8
buf_lect [j++] = 0xC2;
buf_lect [j++] = valcar [l];
}
}
// sinon (cas général)
else
// mémoriser le caractère sans conversion
buf_lect [j++] = valcar [l];
}
}
// sinon si jeu de caractères UTF-8 et on fait un affichage ISO-8859
else if (charset == Utf8 && (! util_utf8 ()))
{
// convertir caractères de UTF-8 en ISO-8859 et les mémoriser
for (l= 0; l < k; l++)
{
// si le caractère est un caractère de controle
if (valcar [l] < 0x20)
{
// et que c'est un caractère autre que CR
if (valcar [l] != '\r')
// le remplacer par un blanc pour
// limiter les problèmes d'affichage
buf_lect [j++] = ' ';
}
// sinon si caractère spécial
else if (valcar [l] & 0x80)
{
// si le caractère précédent était Â
if (buf_lect [j-1] == 0xC2)
// on le remplace par le caractère courant
buf_lect [j-1] = valcar [l];
// sinon si le caractère précédent était Ã
else if (buf_lect [j-1] == 0xC3)
// on le remplace par le caractère courant converti
buf_lect [j-1] = valcar [l] | 0x40;
else
// sinon mémoriser le caractère sans conversion
buf_lect [j++] = valcar [l];
}
// sinon (cas général)
else
// mémoriser le caractère sans conversion
buf_lect [j++] = valcar [l];
}
}
// sinon (jeu de caractère lu = jeu de caractères affiché)
else
{
// simple mémorisation des caractères décodés
for (l= 0; l < k; l++)
{
// si le caractère est un caractère de controle
if (valcar [l] < 0x20)
{
// et que c'est un caractère autre que CR
if (valcar [l] != '\r')
// le remplacer par un blanc pour
// limiter les problèmes d'affichage
buf_lect [j++] = ' ';
}
// sinon (cas général)
else
// mémoriser le caractère sans conversion
buf_lect [j++] = valcar [l];
}
}
}
// sinon, si on a le caractère spécial _
else if (buf_lect [i] == '_' && decode_)
{
// le remplacer par un blanc
buf_lect [j++] = ' ';
// et passer au caractère suivant
i++;
}
// sinon, si on a un caractère de controle
else if (buf_lect [i] < 0x20)
{
// et que c'est un caractère autre que CR
if (buf_lect [i++] != '\r')
// le remplacer par un blanc pour éviter problèmes d'affichage
buf_lect [j++] = ' ';
}
// sinon (cas général : ni encodage ni caractère spécial)
else
{
// prendre en compte les < et > pour éviter de
// convertir les _ en ' ' dans une adresse email
if (buf_lect [i] == '<')
decode_ = 0;
else if (buf_lect [i] == '>')
decode_ = 1;
// on conserve le caractère courant et on passe au suivant
// remarque : on n'a pas jugé utile de convertir le jeu de
// caractères accentués vu qu'il ne devrait pas
// y en avoir sans encodage
buf_lect [j++] = buf_lect [i++];
}
}
// terminaison de la chaine de caractères
buf_lect [j] = '\0';
}
/* convertit la ligne lue en interprétant les caractères
spéciaux et la mémorise dans le buffer de destination */
void memconvbuf (char *bufdest)
{
// on convertit les caractères spéciaux
majlignentete ();
// mémorisation de la ligne après conversion
membuf (bufdest);
}
/* mémorise la ligne lue en dans le buffer de destination */
void membuf (char *bufdest)
{
int i;
i = 0;
// copie tronquée à la longueur max
do
bufdest [i] = buf_lect [i++];
while (i < 79 && buf_lect [i] != '\0' && buf_lect [i] != '\n');
// terminaison de la chaine de caractères
bufdest [i] = '\0';
}
/* retourne le code hexa lu à la position courante */
int hexa (char *chaine)
{
int valcar;
char souschaine [3];
souschaine [0] = chaine [0];
souschaine [1] = chaine [1];
souschaine [2] = '\0';
sscanf (souschaine, "%x", &valcar);
return valcar;
}