/*
Fichier supgrosmail.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 fichiers mail dépassant la taille
limite passée en paramètre, sauf si le mail provient d'un
expéditeur autorisé.
La liste des expéditeurs autorisés pour envoyer de gros mails
est mémorisée dans un fichier.
Si un mail est refusé, un message d'avertissement est généré
à l'intention de celui qui l'a expédié, et est envoyé en copie
au destinataire qui ne reçoit pas ce message.
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
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
long taillemax; // taille maximale des mails acceptés
char adr_mail [120]; // adresse mail de l'utilisateur
char **listexped; // mémorise expéditeurs autorisés pour gros mails
int nb_exped; // nombre d'expéditeurs mémorisés dans listexped
int listegros [szmaxliste]; // numéro des gros mails à tester
long taillegros [szmaxliste]; // taille des gros mails à tester
int szlistegros; // nombre d'éléments dans listegros
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], bufSubject [120];
char adr_exped [120]; // adresse de l'expéditeur du message qu'on filtre
/* compteurs */
int conserves; // nombre de mails conservés
int supprimes; // nombre de mails supprimés
int avertis; // nombre d'expéditeurs de mails supprimés avertis
int non_avertis; // nombre d'expéditeurs de mails supprimés non avertis
/* programme principal */
int main (int nbarg, char *varg[])
{
char serv_smtp [120]; // nom du serveur smtp utilisé
FILE *fconf; // descripteur du fichier de configuration
// fichier contenant les adresses d'expéditeurs à tester
char ficadr_OK [szchemin + 11];
char *car_ficadr_OK; // pointeur sur un caractère de ce fichier
// récupération du nom de l'exécutable
memcom (*varg);
// nombre d'arguments passés en paramètre
nbarg--;
// si utilisation d'un mail de réponse spécifique
if (nbarg == 4 && strcmp (varg [1], "-m") == 0)
{
// mémoriser le nom du fichier contenant le mail de réponse
ficmailrep = varg [2];
// si ce fichier n'existe pas
if (access (ficmailrep, 0) != 0)
errfatale ("MANQUE_FICMAILREP", ficmailrep);
// sauter les argument traités
varg = varg + 2;
nbarg = nbarg - 2;
}
// sinon, mail de réponse standard
else
ficmailrep = NULL;
// controle du nombre d'arguments restants
if (nbarg == 2)
{
// récupérer la taille maximale des mails
// acceptés pour n'importe quel expéditeur
taillemax = atol (varg [1]);
// erreur de syntaxe si la taille maximale est nulle
if (! taillemax)
{
// "Paramètre taille_max incorrect ou mal placé"
affiche_err ("ERR_TAILLEMAX");
return (0);
}
// on peut mettre un - devant le paramètre taille
if (taillemax < 0)
taillemax = -taillemax;
// cette taille peut être exprimée en koctets
if (tolower (varg [1][strlen (varg [1]) - 1]) == 'k')
taillemax *= 1024;
// controle de sécurité :
// si cette taille est très faible, elle doit être confirmée par un !
if (taillemax < taillemin && varg [1][strlen (varg [1]) - 1] != '!')
{
//"Une taille maximale de %ld octets est très faible pour un mail\n"
//"Veuillez la confirmer en la faisant suivre d'un !"
fprintf (stderr, message ("TAILLEMAX_FAIBLE"), taillemax);
affiche_err ("CONFIRM_TAILLE");
return (0);
}
// ouvrir le fichier de configuration
fconf = ouvre_ficonf (varg [2]);
if (fconf)
{
// connexion sur le compte mail du serveur pop
if (connect_pop (fconf))
{
// récupérer la liste des gros mails
listergrosmail (0);
// s'il risque d'y avoir des mails à supprimer
if (szlistegros)
{
// récupérer le nom du répertoire racine de la messagerie
fgets (ficadr_OK, szchemin, fconf);
// fabriquer le chemin d'accès au fichier contenant les
// adresses d'expéditeurs de mails en copie cachée autorisés
// <racine>/accept_gros
car_ficadr_OK = ficadr_OK + strlen (ficadr_OK);
*(car_ficadr_OK - 1) = '/';
strcpy (car_ficadr_OK, ficdir ("FIC_ACCEPT_GROS"));
// si ce fichier existe
if (access (ficadr_OK, 0) == 0)
// charger en mémoire la liste de ces expéditeurs
listexped = charge_valchamp (ficadr_OK, &nb_exped);
else
// sinon liste vide
nb_exped = 0;
// et la mémoriser
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';
// connexion au serveur smtp pour l'envoi des avertissements
if (connect_smtp (serv_smtp))
{
// filtrage des gros mails
filtreliste ();
// si la liste des gros mails avait atteint sa
// taille maximale, mais qu'on a pu en supprimer
// on relance une ou plusieurs étape(s) de filtrage
while (szlistegros == szmaxliste)
{
// récupérer la liste des gros mails restants
listergrosmail (listegros [szlistegros - 1]);
// s'il en reste
if (szlistegros)
{
// les filtrer
// "Nouvelle étape de filtrage"
affiche_msg ("NOUV_ETAPE");
filtreliste ();
}
}
// fermeture de la connexion smtp
deconnect_smtp ();
}
}
else
// "Aucun mail ne dépasse la taille autorisée"
affiche_msg ("AUCUN_GROSMAIL");
// se déconnecter proprement du serveur pop
deconnect_pop ();
}
// on n'a plus besoin du fichier de configuration
fclose (fconf);
}
}
else
// Syntaxe : %s [-m fichier_mail_réponse] taille_max fichier_configuration
psyntaxe ("SYNT_SUPGROSMAIL");
// pour faire plaisir à gcc qui veut une fonction main de type int
return (0);
}
/* mémorise les numéros des mails dépassant la
taille limite et dont le numéro est > numdepart */
void listergrosmail (int numdepart)
{
long numail; // numéro du mail dont on liste la taille
long taillemail; // taille de ce mail
// initialisation
szlistegros = 0;
// mémoriser les tailles des mails
env_pop ("LIST");
// sauter le message d'entête de la liste
lire_pop ();
// lire la taille d'un mail
lire_pop ();
// tantque des mails restent à analyser
while (buf_lect [0] != '.')
{
// récupérer la taille du mail
sscanf (buf_lect, "%ld%ld", &numail, &taillemail);
// si ce mail est trop gros, n'a pas été encore mémorisé comme mail
// à supprimer, et que la liste des mails à supprimer n'est pas pleine
if (taillemail > taillemax && numail > numdepart
&& szlistegros < szmaxliste)
{
// mémoriser le numéro et la taille de ce mail
listegros [szlistegros] = numail;
taillegros [szlistegros++] = taillemail;
}
// lire la taille du mail suivant
lire_pop ();
}
}
/* supprime les gros mails ne provenant pas d'expéditeurs autorisés */
void filtreliste ()
{
int i; // compteur
// initialisation des compteurs de mail traités
conserves = 0;
supprimes = 0;
avertis = 0;
non_avertis = 0;
// test des gros mails et suppression éventuelle
for (i = 0; i < szlistegros; i++)
testfiltre (i);
// message de suivi de déroulement
// "\rControle expéditeur du message : %d"
printf (message ("TEST_EXPED"), numes);
fflush (stdout);
/* demande de lecture de l'entête du message */
sprintf (bufw, "TOP %d 1", 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
// pour cette fonction, on n'a besoin que de la ligne From:
// mais en mémorisant le reste, on évite de relire l'entête
// du mail dans la fonction avertir
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 ("Subject"))
membuf (bufSubject);
}
// lecture terminée si ligne limitée à un .
while (buf_lect [0] != '.' || buf_lect [1] != '\0');
// extraire l'adresse de l'expéditeur
ajout_adr (adr_exped, bufFrom + 5);
// si le mail ne provient pas d'un expéditeur autorisé
if ((! *adr_exped) || (! trouve_valchamp (adr_exped, listexped, nb_exped)))
{
// envoyer un mail à l'expéditeur du message
if (bufFrom [0])
if (avertir (posliste))
avertis ++;
else
non_avertis ++;
// destinataire principal du message
sprintf (bufw, "RCPT TO: <%s>", adr_exped);
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"
printf (message ("REFUS_DEST"), adr_exped);
puts (buf_lect);
// et on n'envoie aucun mail d'avertissement
envoie_smtp ("RSET");
lire_smtp ();
return 0; // mail non envoyé
}
// l'expéditeur du message le recevra en copie
sprintf (bufw, "RCPT TO: <%s>", adr_mail);
envoie_smtp (bufw);
lire_smtp ();
// préparation de l'envoi du message
envoie_smtp ("DATA");
lire_smtp ();
// 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 = 0;
// on s'arrête si l'on rencontre un > , un blanc ou une fin de chaine
while (source [debut] != '>' && source [debut] & 0xDF)
// l'adresse est mémorisée en minuscules
dest [posdest++] = tolower (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