/*
Fichier filtrechamp.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 du serveur comportant une chaine de
caractères particulière dans un champ choisi.
La liste des chaines de caractères interdites est mémorisée dans
un fichier.
Un fichier de configuration est utilisé pour se connecter à la
boite aux lettres.
*/
#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 "testchamp.h"
#include "trtentete.h"
#include "datecour.h"
#include "szchemin.h"
/* prototypes */
int testchamp (int numes, char *nomchamp);
/* variables globales au source
(pour éviter des tonnes de passages de paramètres) */
char **listechamp; // mémorise les champs interdits
int sz_listechamp; // nombre de champs mémorisés dans listechamp
char bufChamp [120]; // buffer contenant le champ du mail à tester
int opto, optO; // options de traitement
// chaine de caractère mémorisée pour éviter appels répétitifs à message ()
char mess_analys [50]; // message signalant l'analyse d'un mail
/* programme principal */
int main (int nbarg, char *varg[])
{
char fichliste [szchemin]; // fichier contenant liste des chaines à tester
FILE *fconf; // descripteur du fichier de configuration
FILE *ftrace; // fichier contenant les champs des mail refusés
char *nomchamp; // nom du champ à tester
char *nomfliste; // nom du fichier contenant les chaines à tester
int numes, nbmes; // muméro du mail courant et nombre de mails
char bufw [120]; // buffer d'envoi d'une requête de destruction de mail
char datecour [10]; // date courante (pour le fichier des mails refusés)
int conserves = 0; // nombre de mails conservés
int supprimes = 0; // nombre de mails supprimés
int i, j; // compteurs
// récupération du nom de l'exécutable
memcom (*varg);
// se positionner sur le premier argument de filtrechamp
nbarg --;
varg ++;
// récupération du nom du champ à tester
if (nbarg > 1)
{
nomchamp = varg [0];
nbarg --;
varg ++;
}
// initialisations valeur des options
ftrace = NULL;
nomfliste = NULL;
opto = 0;
optO = 0;
// si le programme a été lancé avec des options
while (nbarg >= 2 && **varg == '-')
{
// traitement des options
switch (varg [0][1])
{
// option trace des mails supprimés
case 't' : // 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;
break;
// option nom du fichier contenant la liste des chaines autorisées
case 'f' : nomfliste = varg [1];
// sauter les arguments traités
nbarg -= 2;
varg += 2;
break;
// option test de la ligne d'entête d'origine (avant conversion)
case 'o' : if (! optO)
opto = 1;
else
// "L'option -O est prioritaire sur l'option -o"
affiche_err ("PRIO_OPT_O");
// sauter l'argument traité
nbarg --;
varg ++;
break;
// option test de la ligne d'entête d'origine (avant conversion)
case 'O' : optO = 1;
if (opto)
// "L'option -O est prioritaire sur l'option -o"
affiche_err ("PRIO_OPT_O");
// sauter l'argument traité
nbarg --;
varg ++;
break;
// aucune autre option n'est reconnue
// "Option %s incorrecte"
default : aff_err_arg ("ERR_OPTION", *varg);
nbarg = 0; // pour rappeller la syntaxe
}
}
// controle du nombre d'arguments restants
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))
{
// détermination du nom du fichier
// contenant les chaines interdites
// cas particulier : chemin d'accès absolu à ce fichier
if (nomfliste && *nomfliste == '/')
strcpy (fichliste, nomfliste);
else
{
// cas général : pas de chemin d'accès absolu au fichier
// récupération du répertoire racine de la messagerie
fgets (fichliste, sizeof (fichliste), fconf);
// on complète ce nom d'un /
strcpy (fichliste + strlen (fichliste) - 1, "/");
// si le nom de ce fichier a été passé en paramètre
if (nomfliste)
// le rajouter au nom du répertoire
strcat (fichliste, nomfliste);
else
{
// sinon, on va générer un nom à partir du nom du champ
strcat (fichliste, ficdir ("FIC_REFUS_"));
i = strlen (fichliste);
j = 0;
do
// le nom du champ est recopié en minuscules
fichliste [i++] = tolower (nomchamp [j]);
while (nomchamp [j++]);
}
}
// charger en mémoire les champs interdits
listechamp = charge_valchamp (fichliste, &sz_listechamp);
// si la liste n'est pas vide
if (sz_listechamp)
{
// récupération du nombre de mails
nbmes = nbmails ();
// Initialisation du message à afficher
// à chaque analyse de mail
// "\rAnalyse du mail n° %d"
strcpy (mess_analys, message ("ANALYSE_MAIL"));
// vérification des différents mails
for (numes = 1; numes <= nbmes; numes++)
{
// si le champ du mail contient une chaine interdite
if (testchamp (numes, nomchamp))
{
// demande de destruction du mail
sprintf (bufw, "DELE %d", numes);
env_pop (bufw);
lire_pop ();
supprimes ++;
// si utilisation d'un fichier trace
if (ftrace)
// mémoriser le champ de ce mail
fprintf (ftrace, "%s%s\n", datecour, bufChamp);
}
else
conserves ++;
}
// édition d'un récapitulatif
// "\n%d messages conservés, %d supprimés\n"
printf (message ("BILAN_FILTRAGE"), conserves, supprimes);
}
// 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 nom_champ [-f fich_liste]
// [-(o|O)] [-t fich_trace] fich_configuration"
psyntaxe ("SYNT_FILTRECHAMP");
return (0);
}
/* lit l'entête d'un mail et vérifie si son champ est autorisé */
int testchamp (int numes, char *nomchamp)
{
char bufw [120]; // buffer d'envoi d'une requête
char champbrut [120]; // buffer contenant le champ du mail avant décodage
int debchamp; // position du premier caractère significatif du champ
// "\rAnalyse du mail n° %d"
printf (mess_analys, numes);
fflush (stdout);
// initialisations
bufChamp [0] = '\0';
champbrut [0] = '\0';
// demande de lecture de l'entête du message
sprintf (bufw, "TOP %d 1", numes);
env_pop (bufw);
// lire la première ligne de l'entête du message
lire_pop ();
// terminé pour ce mail si erreur d'envoi coté serveur
if (memcmp (buf_lect, "-ERR ", 5) == 0)
{
// Erreur serveur pour l'accès au mail
aff_err_argnum ("ERREUR_SERVEUR", numes);
return 0;
}
// lecture entête du message et mémorisation de le champ du mail
do
{
// si on a trouvé le champ choisi
if (start (nomchamp))
{
// recherche du premier caractère significatif du champ
debchamp = strlen (nomchamp) + 1;
while (buf_lect [debchamp] == ' ')
debchamp++;
// si option -o ou -O
if (opto || optO)
{
// mémoriser le champ du mail avant conversion en le tronquant
// si nécessaire pour éviter un débordement de tableau
if (strlen (buf_lect + debchamp) >= sizeof (champbrut))
{
memcpy (champbrut, buf_lect + debchamp, sizeof (champbrut));
champbrut [sizeof (champbrut) - 1] = '\0';
}
else
strcpy (champbrut, buf_lect + debchamp);
}
// si on n'utilise pas l'option -O
if (! optO)
{
// convertir les caractères spéciaux de la ligne
majlignentete ();
// tronquer si nécessaire le champ
if (strlen (buf_lect + debchamp) >= sizeof (bufChamp))
buf_lect [debchamp + sizeof (bufChamp) - 1] = '\0';
// mémorisation du champ converti
strcpy (bufChamp, buf_lect + debchamp);
}
}
// lire la ligne suivante de l'entête du message
lire_pop ();
}
// lecture terminée si ligne limitée à un .
while (buf_lect [0] != '.' || buf_lect [1] != '\0');
// vérifier si le mail contient un des champs de la liste interdite
if (optO)
// option -O : test sur le champ brut seulement
return trouve_valchamp (champbrut, listechamp, sz_listechamp);
else if (opto)
{
// option -o (seule) : test sur le champ brut et le champ converti
return (trouve_valchamp (champbrut, listechamp, sz_listechamp)
|| trouve_valchamp (bufChamp, listechamp, sz_listechamp));
}
else
// aucune option : test sur le champ converti seulement
return trouve_valchamp (bufChamp, listechamp, sz_listechamp);
}