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 rajoute des fichiers joints à un mail à envoyer.
Le nom du fichier mail concerné est passé en paramètre.
Le chemin d'accès au fichier peut être absolu ou relatif
*/
#define appli // pour la déclaration de variables globales à l'application
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
FILE *descfic; // descripteur du fichier à joindre
int ajouts = 0; // pour éviter défauts si aucun fichier n'est rajouté
/* programme principal */
int main (int nbarg, char *varg[])
{
// récupération du nom de l'exécutable
memcom (*varg);
// controle du nombre d'arguments
if (--nbarg >= 1)
{
// si le fichier mail existe
if (access (varg [1], 0) == 0)
{
// passer le mail en mode multipart/mixed si nécessaire
prepar_mail (varg [1]);
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* passe le mail en mode multipart/mixed s'il n'y est pas déjà */
void prepar_mail (char *nomfmail)
{
long posfic; // position dans le fichier en début de ligne
long posContent; // position au début du champ Content-Type
char bufEncode [120]; // contenu du champ Content-Transfer-Encoding
char fictmp [120]; // fichier tampon pour passer en mode multipart/mixed
FILE *desctmp; // descripteur du fichier fictmp
int typederlig; // mémorise si la dernière ligne du message est blanche
// ouvrir le fichier mail en lecture/écriture
fmail = fopen (nomfmail, "r+");
// erreur fatale si ouverture refusée
if (! fmail)
{
// "Impossible de mettre à jour le fichier %s"
errfatale ("IMPOS_MAJ_FICH", nomfmail);
}
// lecture du fichier mail jusqu'au champ Content-Type
while (lire_fmail () && ! start ("Content-Type"))
;
// si le fichier n'est pas encore mode multipart/mixed
if (recup_ctype () != MultipMixed)
{
// fabriquer un nom de fichier tampon
strcpy (fictmp, nomfmail);
strcat (fictmp, ".t");
// et l'ouvrir en écriture
desctmp = fopen (fictmp, "w");
// erreur fatale si ouverture refusée
if (! desctmp)
{
// "Impossible de mettre à jour le fichier %s"
errfatale ("IMPOS_MAJ_FICH", nomfmail);
}
// revenir au debut du fichier mail
rewind (fmail);
lire_fmail ();
// recopier son entête sans les champs Content-T...
while (lire_fmail () && *buf_lect)
{
// si champ Content-Type
if (start ("Content-Type"))
{
// on mémorise la position de la ligne
posContent = posfic;
// et on lit jusqu'à la dernière ligne du champ
do
lire_fmail ();
while (*buf_lect == ' ' || *buf_lect == '\t');
}
// si champ Content-Transfer-Encoding
if (start ("Content-Transfer-Encoding"))
// on mémorise la ligne
membuf (bufEncode);
// sinon
else
{
// on recopie le ligne dans le fichier tampon
fputs (buf_lect, desctmp);
fputc ('\n', desctmp);
}
// récupérer la position de début de la ligne suivante
posfic = ftell (fmail);
}
// générer une bordure avec une partie aléatoire
sprintf (bordure [0], "-LIBREMAIL-BORDURE-id=%08lX%03X-", time (0),
getpid ());
// générer le nouveau champ Content-Type
fprintf (desctmp, "Content-Type: multipart/mixed; boundary=\"%s\"\n",
bordure [0]);
// première section : générer la bordure
fprintf (desctmp, "\n--%s\n", bordure [0]);
// le champ Content-Type
if (posContent >= 0)
{
// on se positionne dessus pour le recopier
fseek (fmail, posContent, SEEK_SET);
lire_fmail ();
// répéter
do
{
// recopier la ligne
fprintf (desctmp, "%s\n", buf_lect);
// et lire la suivante
lire_fmail ();
}
// jusqu'à la fin de ce champ
while (*buf_lect == ' ' || *buf_lect == '\t');
}
else
{
// jeu de caractères du message
fputs ("Content-Type: text/plain; charset=", desctmp);
// le champ Content-Transfer-Encoding
if (*bufEncode)
fputs (bufEncode, desctmp);
else
fputs ("Content-Transfer-Encoding: 8bit", desctmp);
// + passage à la ligne
fputc ('\n', desctmp);
// revenir sur le texte du mail
fseek (fmail, posfic, SEEK_SET);
// le recopier jusqu'en fin de fichier
while (lire_fmail ())
{
// recopier la ligne
fprintf (desctmp, "%s\n", buf_lect);
// mémoriser si longueur nulle
typederlig = *buf_lect;
}
// rajouter une ligne blanche si nécessaire
if (typederlig)
fputc ('\n', desctmp);
// générer la bordure finale
fprintf (desctmp, "--%s--\n", bordure [0]);
// fermer les fichiers
fclose (desctmp);
fclose (fmail);
// et remplacer l'ancien fichier par le nouveau
unlink (nomfmail);
rename (fictmp, nomfmail);
}
// sinon (fichier déjà en mode multipart/mixed)
else
{
// mémoriser la bordure
while (*buf_lect && ! mem_boundary ())
lire_fmail ();
// et fermer le fichier (on le réouvrira dans ajout_fich)
fclose (fmail);
}
}
/* rajoute les fichiers joints au mail */
void ajout_fich (int narg, char **varg)
{
char chemfich [120]; // vom de fichier à joindre saisi au clavier
int i; // compteur
// ouvrir le fichier mail en lecture/écriture
fmail = fopen (*varg, "r+");
// traitement d'une erreur qui ne devrait jamais arriver
if (!fmail)
{
// "Erreur 2ème ouverture fichier mail !!!"
affiche_err ("ERR_OUVERT_2");
return;
}
// si des noms de fichiers à joindre ont été passés en paramètre
if (narg > 0)
{
// les rajouter en pièce jointe un par un
for (i = 1; i <= narg; i++)
joinfich (varg [i]);
}
// sinon, on va saisir leur nom au clavier
else
{
// retour à la configuration standard du clavier si nécessaire
system ("stty icanon echo");
do
{
// "Nom de fichier à joindre ? (touche entrée quand il n'y en a plus)"
affiche_msg ("NOUV_FICJOINT");
// on lit avec fgets pour éviter le warning de compilation de gets
// puis on enlève le \n en trop (que gets ne met pas)
fgets (chemfich, sizeof (chemfich), stdin);
chemfich [strlen (chemfich) - 1] = '\0';
if (*chemfich)
joinfich (chemfich);
}
while (*chemfich); // liste terminée lorsque ligne vide
}
// si on a rajouté des fichiers
if (ajouts)
{
// corriger la dernière bordure
fseek (fmail, -1, SEEK_END);
fputs ("--\n", fmail);
}
// le fichier mail est prêt
fclose (fmail);
}
/* rajoute un fichier joint au mail */
void joinfich (char *chemfich)
{
int car; // caractère du fichier à joindre
int normal, special; // compteurs de caractères
char nomfich [30]; // nom du fichier joint (sans le chemin)
int i, j; // compteurs
// ouvrir en lecture le fichier à joindre
descfic = fopen (chemfich, "r");
// si ouvert
if (descfic)
{
// initialisation
normal = 0;
special = 0;
// on va déterminer le mode d'encodage le moins encombrant
car = getc (descfic);
// tant que non fin de fichier
while (car != EOF)
{
// comptabiliser ce caractère dans la bonne catégorie
if ((car < 0x20 && car != '\t') || car == '=' || car > 0X7E)
special++;
else
normal++;
// continuer avec le caractère suivant
car = getc (descfic);
}
// si pas encore de fichier rajouté
if (!ajouts)
{
// supprimer 2 - à la dernière bordure
fseek (fmail, -3, SEEK_END);
fputc ('\n', fmail);
// cette correction n'est faite qu'une fois
ajouts = 1;
}
// fabriquer le nom du fichier joint à partir du chemin
j = 0;
for (i = 0; chemfich [i]; i++)
{
// on supprime le nom de répertoire du fichier à joindre
if (chemfich [i] == '/' || chemfich [i] == '\\')
j = 0;
// ainsi que les blancs dans le nom de fichier
else if (chemfich [i] != ' ')
nomfich [j++] = chemfich [i];
// choisir le mode d'encodage pour joindre la pièce
if (special * 5 <= normal)
ajout_quoted ();
else
ajout_base64 ();
// générer la bordure terminale
fprintf (fmail, "--%s\n", bordure [0]);
// terminé avec ce fichier
fclose (descfic);
}
// sinon, message d'erreur
else if (access (chemfich, 0) < 0)
// "Fichier %s inexistant"
aff_err_arg ("FICH_INEXISTANT", chemfich);
else
// "Fichier %s protégé en lecture"
aff_err_arg ("ACCES_FICH_LECT", chemfich);
}
/* encode le fichier à joindre en quoted-printable */
void ajout_quoted ()
{
int car; // caractères du fichier à joindre
int posligne; // position dans la ligne courante du fichier mail
// terminaison de l'entête de la pièce jointe
fputs ("Content-Transfer-Encoding: quoted-printable\n\n", fmail);
// initialisation
posligne = 1;
car = getc (descfic);
// tant que non fin de fichier
while (car != EOF)
{
// traitement particulier du caractère CR
if (car == '\r')
{
// lire le caractère suivant
car = getc (descfic);
// si c'est un LF
if (car == '\n')
{
// passage à la ligne sans le \r qui
// sera rajouté à l'expédition du mail
fputc ('\n', fmail);
posligne = 1;
}
// sinon
else
{
// encoder le CR comme les autres caractères spéciaux
fputs ("=0D", fmail);
posligne = posligne + 3;
// on traitera le caractère qui suit plus tard
ungetc (car, descfic);
}
// si CR LF un passage à la ligne sera généré plus loin
}
// autres caractères spéciaux
else if ((car < 0x20 && car != '\t') || car == '=' || car > 0X7E)
{
// passage à la ligne si la précédente était trop longue
if (posligne > 72)
{
fputs ("=\n", fmail);
posligne = 1;
}
// ces caractères sont encodés
fprintf (fmail, "=%02X", car);
if (car == '\n')
{
fputs ("=\n", fmail); // pour la lisibilité
posligne = 1;
}
else
posligne = posligne + 3;
}
// caractères normaux
else
{
// passage à la ligne si la précédente était trop longue
if (posligne > 74)
{
fputs ("=\n", fmail);
posligne = 1;
}
// ces caractères sont juste recopiés
putc (car, fmail);
posligne ++;
}
// passer au caractère suivant
car = getc (descfic);
}
}
/* encode le fichier à joindre en base64 */
void ajout_base64 ()
{
char bufin [58]; // tableau contenant des données du fichier à joindre
char bufout [77]; // données de bufin converties base64
int nbcar; // nombre de caractères récupérés dans bufin
// terminaison de l'entête de la pièce jointe
fputs ("Content-Transfer-Encoding: base64\n\n", fmail);
// lire de quoi générer une ligne encodée base64
nbcar = fread (bufin, 1, 57, descfic);
// si le fichier joint n'est pas vide
if (nbcar)
{
// répéter
do
{
// encoder les données base64 et les copier dans le fichier mail
encode64 (bufin, bufout, nbcar);
fputs (bufout, fmail);
fputc ('\n', fmail);
// lire de quoi générer une ligne de plus
nbcar = fread (bufin, 1, 57, descfic);
}
// jusqu'à fin de fichier
while (nbcar);
}
}