/*
Fichier suphtm.c
Auteur Bernard Chardonneau
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 détruit les mails écrits en HTML pur.
Ce format de mail très rarement utilisé par des particuliers
est par contre beaucoup plus fréquent dans les spams.
Un message est généré à l'intention de l'expéditeur du mail
non récupéré.
Un fichier de configuration est utilisé pour se connecter à la
boite aux lettres et pour sélectionner le serveur SMTP servant
à l'envoi des messages.
*/
#define appli // pour la déclaration de variables globales à l'application
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "messages.h"
#include "buflect.h"
#include "ficonf.h"
#include "pop.h"
#include "smtp.h"
#include "trtentete.h"
#include "datecour.h"
#include "mailrep.h"
#include "genchampdate.h"
/* prototypes */
void filtremail (int numes);
int avertir ();
void ajout_adr (char *dest, char *source);
void transf_ligne (char *message);
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
char adr_mail [120]; // adresse mail de l'utilisateur
char pref_adr [120]; // préfixe vraie adresse mail pour la masquer aux
// robots qui traitent les réponses aux spams
FILE *ftrace; // Fichier contenant les adresses d'expéditeurs refusés
char datecour [10]; // Date courante (pour le fichier d'expéditeurs refusés)
int opte; // Option -e (mails refusés non signalés à adresse Reply-To)
int opts; // Option -s (mails refusés non signalés aux expéditeurs)
int etat_smtp = 0; // état de la connexion smtp
char serv_smtp [120]; // nom du serveur smtp utilisé
char *ficmailrep; // fichier comptenant un mail pour réponse spécifique
/* buffers rappelant les caractéristiques du message */
char bufDate [120], bufFrom [120], bufTo [120], bufCc [120], bufReply [120],
bufSubject [120], bufContent [120], bufRetPath [120];
/* compteurs */
int conserves = 0;
int supprimes = 0;
int avertis = 0;
int non_avertis = 0;
/* programme principal */
int main (int nbarg, char *varg[])
{
FILE *fconf; // descripteur du fichier de configuration
int numes, nbmes; // numéro du mail courant et nombre de mails
// récupération du nom de l'exécutable
memcom (*varg);
// se positionner sur le premier argument de suphtm
nbarg --;
varg ++;
// initialisation des options de suphtm
*pref_adr = '\0';
ftrace = NULL;
ficmailrep = NULL;
opte = 0;
opts = 0;
// prise en compte des options de suphtm
while (nbarg > 1 && **varg == '-')
{
// option -m (utilisation d'un mail de réponse spécifique)
if (varg [0][1] == 'm')
{
// mémoriser le nom du fichier contenant le mail de réponse
ficmailrep = varg [1];
// si ce fichier n'existe pas
if (access (ficmailrep, 0) != 0)
errfatale ("MANQUE_FICMAILREP", ficmailrep);
// sauter les argument traités
nbarg -= 2;
varg += 2;
}
// option -p (préfixe dans l'adresse d'expéditeur)
else if (varg [0][1] == 'p')
{
// préfixe par défaut
if (varg [0][2] == 'd')
{
strcpy (pref_adr, "suphtm");
// sauter l'argument traité
nbarg --;
varg ++;
}
// préfixe passé en paramètre
else if (varg [0][2] == '\0')
{
strcpy (pref_adr, varg [1]);
// sauter les arguments traités
nbarg -= 2;
varg += 2;
}
}
// option -e (pas de mail d'avertissement à l'adresse du champ
// Reply-To en plus de l'adresse de l'expéditeur)
else if (strcmp (*varg, "-e") == 0)
{
opte = 1;
// sauter l'argument traité
nbarg --;
varg ++;
}
// option -s (pas de mail d'avertissement lorsque mail HTML détruit)
else if (strcmp (*varg, "-s") == 0)
{
opts = 1;
// sauter l'argument traité
nbarg --;
varg ++;
}
// option -t (utilisation d'un fichier trace)
else if (strcmp (*varg, "-t") == 0)
{
// ouvrir le fichier trace en écriture fin de fichier
ftrace = fopen (varg [1], "a");
// si nom de fichier correct
if (ftrace)
// initialiser la date courante
initdatecour (datecour);
else
// sinon, avertir l'utilisateur
// "Impossible d'écrire dans le fichier %s"
aff_err_arg ("IMPOS_ECR_FICH", varg [1]);
// sauter les arguments traités
nbarg -= 2;
varg += 2;
}
// option incorrecte
else
{
// "Option %s incorrecte"
aff_err_arg ("ERR_OPTION", *varg);
nbarg = 0; // on terminera en affichant la syntaxe de la commande
}
}
// aucun traitement si option -e et -s utilisées simultanément
if (opte && opts)
// "Option -e et -s incompatibles"
affiche_err ("COMPAT_OPT_ES");
// aucun traitement si option -m et -s utilisées simultanément
else if (ficmailrep && opts)
// "Option -m et -s incompatibles"
affiche_err ("COMPAT_OPT_MS");
// idem si option -p et -s utilisées simultanément
else if (*pref_adr && opts)
// "Option -p et -s incompatibles"
affiche_err ("COMPAT_OPT_PS");
// sinon, controle du nombre d'arguments restants
else if (nbarg == 1)
{
// ouvrir le fichier de configuration
fconf = ouvre_ficonf (*varg);
if (fconf)
{
// connexion sur le compte mail du serveur pop
if (connect_pop (fconf))
{
// récupération du nombre de mails
nbmes = nbmails ();
// on saute la ligne contenant le répertoire des mails
while (fgetc (fconf) != '\n')
;
// recupérer adresse mail utilisateur
fgets (buf_lect, sizeof (buf_lect), fconf);
buf_lect [strlen (buf_lect) - 1] = '\0';
// et la mémoriser
*adr_mail = '\0';
ajout_adr (adr_mail, buf_lect);
// recupérer le nom du serveur smtp
fgets (serv_smtp, 120, fconf);
serv_smtp [strlen (serv_smtp) - 1] = '\0';
// s'il y a des mails à tester
if (nbmes > 0)
{
// filtrage de la liste des mails
for (numes = 1; numes <= nbmes; numes++)
filtremail (numes);
// édition d'un récapitulatif
// "\n%d messages conservés, %d supprimés\n"
printf (message ("BILAN_FILTRAGE"), conserves, supprimes);
if (supprimes && (opts == 0))
// "%d expéditeurs avertis, %d non avertis\n"
printf (message ("BILAN_AVERTIS"), avertis,
non_avertis);
// fermeture de la connexion smtp si elle a été ouverte
if (etat_smtp)
deconnect_smtp ();
}
// se déconnecter proprement du serveur pop
deconnect_pop ();
// si des mails ont été supprimés
if (supprimes)
// attendre pour enregistrement correct des suppressions
// (évite problème si autre filtre appelé juste après)
sleep (2);
}
// on n'a plus besoin du fichier de configuration
fclose (fconf);
}
}
else
{
// "Syntaxe : %s [-pd|-p préfixe] [-e|-s] [-m fichier_mail_réponse]"
// [-t fichier_adresses] fichier_configuration"
psyntaxe2 ("SYNT_SUPHTM1", "SYNT_SUPHTM2");
}
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* vérifie si le message choisi est en HTML pur, et
le détruit dans ce cas en avertissant l'expéditeur */
void filtremail (int numes)
{
char bufw [120]; // buffer d'envoi d'une requête
int posbuf; // simple compteur
// initialisation
bufDate [0] = '\0';
bufFrom [0] = '\0';
bufTo [0] = '\0';
bufCc [0] = '\0';
bufReply [0] = '\0';
bufSubject [0] = '\0';
bufContent [0] = '\0';
bufRetPath [0] = '\0';
// message de suivi de déroulement
// "\rAnalyse du mail n° %d "
printf (message ("ANALYSE_MAIL"), numes);
fflush (stdout);
/* demande de lecture de l'entête du message
On demande 5 lignes du corps du message pour trouver le
2ème Content-type si le premier est multipart/mixed */
sprintf (bufw, "TOP %d 5", numes);
env_pop (bufw);
// lecture et mémorisation des caractéristiques du message
do
{
// lire une ligne de l'entête du message
lire_pop ();
// convertir les caractères spéciaux
majlignentete ();
// mémorisation des caractéristiques importantes
if (start ("Date"))
membuf (bufDate);
else if (start ("From"))
membuf (bufFrom);
else if (start ("To"))
membuf (bufTo);
else if (start ("Cc"))
membuf (bufCc);
else if (start ("Reply-To"))
membuf (bufReply);
else if (start ("Subject"))
membuf (bufSubject);
else if (start ("Content-Type"))
membuf (bufContent);
else if (start ("Return-Path"))
membuf (bufRetPath);
}
// lecture terminée si ligne limitée à un .
while (buf_lect [0] != '.' || buf_lect [1] != '\0');
// si le mail contenait une ligne Content-Type
if (*bufContent)
{
// positionnement sur le 2ème attribut de Content_type
// nécessaire pour bonne détection s'il y à 0 ou plus
// d'un blanc après le : du Content-Type
posbuf = 17;
while (bufContent [posbuf] != '/')
posbuf++;
}
// si le mail est en HTML pur
if (*bufContent && tolower (bufContent [posbuf+1]) == 'h'
&& tolower (bufContent [posbuf+2]) == 't')
{
// demande de destruction du message
sprintf (bufw, "DELE %d", numes);
env_pop (bufw);
lire_pop ();
supprimes ++;
// si utilisation d'un fichier trace
if (ftrace)
// mémoriser l'adresse de l'expéditeur dans ce fichier
fprintf (ftrace, "%s%s\n", datecour, bufFrom + 5);
// envoyer un mail à l'expéditeur, sauf si option -s
if (! opts && (bufFrom [0] || bufRetPath [0]))
{
// si la connexion smtp n'a pas encore été ouverte
if (! etat_smtp)
{
// ouvrir cette connexion et mémoriser son ouverture
if (connect_smtp (serv_smtp))
etat_smtp = 1;
else
etat_smtp = -1;
}
// avertir si possible l'expéditeur et mémorise l'avertissement
if ((etat_smtp > 0) && avertir ())
avertis ++;
else
non_avertis ++;
}
}
else
conserves ++;
}
/* avertit l'expéditeur d'un mail en HTML pur que son message est refusé */
int avertir ()
{
char bufw [120]; // buffer d'envoi d'une ligne ou d'une requête smtp
// l'envoi du mail d'avertissement suppose l'accès à un fichier de données
if (! acces_mailrep (NULL, "suphtm"))
return (0);
// expéditeur du message
sprintf (bufw, "MAIL FROM: <%s>", adr_mail);
envoie_smtp (bufw);
lire_smtp ();
// destinataire du message
strcpy (bufw, "RCPT TO: <");
// si pas d'option -e, on envoie en priorité à l'adresse du Return_Path
if (!opte && bufRetPath [0])
ajout_adr (bufw, bufRetPath + 12);
// sinon on envoie à l'expéditeur déclaré
else
ajout_adr (bufw, bufFrom + 5);
strcat (bufw, ">");
envoie_smtp (bufw);
lire_smtp ();
// si destinataire refusé, on le signale
if (buf_lect [0] != '2')
{
// Affichage de l'adresse à problème
// "Destinataire %s refusé\n"
putchar ('\n');
printf (message ("REFUS_DEST"), bufw + 9);
puts (buf_lect);
// on n'envoie pas de mail
envoie_smtp ("RSET");
lire_smtp ();
return 0; // mail non envoyé
}
// préparation de l'envoi du message
envoie_smtp ("DATA");
lire_smtp ();
// génération de l'entête du message
// Champ date
gen_champ_date (bufw);
envoie_smtp (bufw);
// si préfixe, l'adresse expéditeur est modifiée dans
// l'entête du message pour tromper les robots de spam
if (*pref_adr)
sprintf (bufw, "From: <%s-%s>", pref_adr, adr_mail);
else
sprintf (bufw, "From: <%s>", adr_mail);
envoie_smtp (bufw);
sprintf (bufw, "To%s", bufFrom + 4);
envoie_smtp (bufw);
// "Subject: Votre message du ..."
sprintf (bufw, "Subject: %s %s", chaine_mailrep ("SUJET"), bufDate + 4);
envoie_smtp (bufw);
// "Content-Type: text/plain; charset=..."
sprintf (bufw, "Content-Type: text/plain; charset=%s",
chaine_mailrep ("CHARSET"));
envoie_smtp (bufw);
envoie_smtp ("Content-Transfer-Encoding: 8bit");
// "filtre suphtm : logiciel libre multilingue"
sprintf (bufw, "User-Agent: filtre %s : %s\n", nomcom (),
message ("QUALIF_LIBREMAIL"));
envoie_smtp (bufw);
envoie_smtp ("");
// "Vous m'avez envoyé un mail ayant les caractéristiques suivantes :"
envoie_smtp (chaine_mailrep ("ANNONCE"));
envoie_smtp ("");
// rappel du message concerné
transf_ligne (bufDate);
transf_ligne (bufFrom);
transf_ligne (bufTo);
transf_ligne (bufCc);
transf_ligne (bufReply);
transf_ligne (bufSubject);
transf_ligne (bufContent);
envoie_smtp ("");
// envoi du message explicatif
envoi_mailrep ();
// indicateur de fin du message
envoie_smtp (".");
lire_smtp ();
return 1; // bon déroulement
}
/* récupère l'adresse mail entre les < > s'ils
existent et la rajoute au buffer destination */
void ajout_adr (char *dest, char *source)
{
int orig, debut, posdest;
orig = 0;
// chercher le @
while (source [orig] != '@' && source [orig])
orig ++;
// remonter au debut de l'adresse
while (orig > 0 && source [orig] != ' ' && source [orig] != '<')
orig--;
// l'adresse commence sur un caractère significatif
if (source [orig] == '<' || source [orig] == ' ')
debut = orig + 1;
else
debut = orig;
// copie de l'adresse
posdest = strlen (dest);
// on s'arrête si l'on rencontre un > , un blanc ou une fin de chaine
while (source [debut] != '>' && source [debut] & 0xDF)
dest [posdest++] = source [debut++];
// terminer l'expression de l'adresse
dest [posdest] = '\0';
}
/* copie dans le mail à envoyer d'une ligne du mail reçu */
void transf_ligne (char *message)
{
char bufw [82]; // buffer contenant la ligne à envoyer
if (*message)
{
strcpy (bufw, "> ");
strcpy (bufw + 2, message);
envoie_smtp (bufw);
}
}