/* ***********************IMPORTANT *********************************************
 *  Copyright (C) 2004-2007 Thierry Lagarde <tlagarde@users.sourceforge.net>
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License.
 *
 *
 *                      ********************
 *
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *
 *                      ********************
 *
 *
 * You are highly encouraged to send your changes to <tlagarde@users.sourceforge.net>
 * for possible incorporation into the main distribution.
 * By sending these changes to <tlagarde@users.sourceforge.net>,
 * it is assumed that you are offering <tlagarde@users.sourceforge.net>
 * the unlimited, non-exclusive right to reuse, modify, and relicense the code.
 *
 *
 *                      ********************
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **************************************************************************************/
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include "Log.h"
#include "Debug.h"
#include "Macro.h"

#ifdef __LOG_ENABLE

struct Struct_Categorie Liste_Categorie[] = {
	{CATEG_MAIN, "Main",REPERTOIRE_LOG "main_daemon",-1,0,FALSE},
	{CATEG_THREAD_DETECT, "Thread Detect",REPERTOIRE_LOG "thread_detect",-1,0,FALSE},
	{CATEG_THREAD_SCAN, "Thread Scan equipement",REPERTOIRE_LOG_EQUIPEMENT "equipement_%s",-1,0,FALSE},
	{CATEG_THREAD_NOTIF_PORT, "Thread Notification Port",REPERTOIRE_LOG "thread_notif_port",-1,0,FALSE},
	{CATEG_THREAD_NOTIF_EQU, "Thread Notification équipement",REPERTOIRE_LOG "thread_notif_equi",-1,0,FALSE},
	{CATEG_BOUCLE_COMMUNIC, "Thread Boucle Communication",REPERTOIRE_LOG "thread_boucle_comm",-1,0,FALSE},
	{CATEG_RAFFRAICHIR_EQU, "Thread Rafraichir Tout Equipement",REPERTOIRE_LOG "thread_rafrai_equ",-1,0,FALSE},
	{CATEG_NESSUS, "CATEG_NESSUS",REPERTOIRE_LOG "thread_nessus",-1,0,FALSE},
	{CATEG_THREAD_SNMP_LISTE_ALL, "CATEG_THREAD_SNMP_LISTE_ALL",REPERTOIRE_LOG "thread_snmp_liste_all",-1,0,FALSE},
	{CATEG_THREAD_SNMP_LISTE, "CATEG_THREAD_SNMP_LISTE",REPERTOIRE_LOG "thread_snmp_liste",-1,0,FALSE},
	{CATEG_BOUCLE_SCAN, "CATEG_BOUCLE_SCAN",REPERTOIRE_LOG "thread_boucle_scan",-1,0,FALSE},
	{CATEG_INFO_AGENT, "CATEG_INFO_AGENT",REPERTOIRE_LOG "thread_info_agent",-1,0,FALSE},
	{CATEG_PING_DETECT, "CATEG_PING_DETECT",REPERTOIRE_LOG "thread_ping_detect",-1,0,FALSE},
	{CATEG_SCAN_PLAGE, "CATEG_SCAN_PLAGE",REPERTOIRE_LOG "thread_scan_plage",-1,0,FALSE},
	{CATEG_THREAD_ETAT_EQUIPEMENT, "CATEG_THREAD_ETAT_EQUIPEMENT",REPERTOIRE_LOG "thread_etat_equi",-1,0,FALSE},
	{CATEG_THREAD_WAKEUP, "CATEG_THREAD_WAKEUP",REPERTOIRE_LOG "thread_wakeup",-1,0,FALSE},
	{CATEG_IP_DYNAMIC, "CATEG_IP_DYNAMIC",REPERTOIRE_LOG "thread_ip_dyn",-1,0,FALSE},
	{CATEG_THREAD_SNMP_SCALAIRE, "CATEG_THREAD_SNMP_SCALAIRE",REPERTOIRE_LOG "thread_snmp_scalaire",-1,0,FALSE},
	{CATEG_COMM_SEND, "CATEG_COMM_SEND", REPERTOIRE_LOG "send_%s",-1,0,FALSE},
	{CATEG_COMM_RECV, "CATEG_COMM_RECV", REPERTOIRE_LOG "recv_%s",-1,0,FALSE}
};



void create_cle_privee (void)
{
	if (pthread_key_create (&Cle_privee_thread, NULL) == -1)
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "pthread_key_create");
}



void Log (struct struct_Cle_Privee *Donnee_Cle,gchar *Log){
#ifdef __LOG_ENABLE
	ERROR_if (Donnee_Cle == NULL);
	ERROR_if (Log == NULL);
	PROTECT_CODE(Semaphore_Log_File);
	gint Taille_Chaine;
	
	if (Donnee_Cle->ID_Fichier_Log > 0){
		Taille_Chaine = strlen(Log);
		if (Taille_Chaine!=write(Donnee_Cle->ID_Fichier_Log,Log,Taille_Chaine)){
			printf("ERROR : Create log  (write)\n");
			DEPROTECT_CODE(Semaphore_Log_File);
			exit (-1);
		}
	}
	DEPROTECT_CODE(Semaphore_Log_File);
#endif	
}

void Log_free (struct struct_Cle_Privee *Donnee_Cle,gchar *Texte){
	if (Texte != NULL){
		Log(Donnee_Cle,Texte);
		MYFREE(Texte);
	}
}


struct struct_Cle_Privee *Create_Log (gint Categorie,gchar *name,void *Data,gboolean Attache_Thread){
#ifdef __LOG_ENABLE
	PROTECT_CODE(Semaphore_Log_File);	
	struct struct_Cle_Privee *Donnee_Cle = NULL;
	gchar	*Entete = NULL,*Fichier_Log = NULL;
	
	if (Attache_Thread)
		pthread_once(&once_cle_privee,create_cle_privee);
	MALLOC(Donnee_Cle,sizeof(struct struct_Cle_Privee));
	Donnee_Cle->Categorie = Categorie;
	Donnee_Cle->Pointeur_Data = Data;


	if ((Liste_Categorie[Categorie].used==0)  || ( Categorie == CATEG_THREAD_SCAN) || (name!=NULL)) {
		if (name!=NULL)
			Fichier_Log = g_strdup_printf(Liste_Categorie[Categorie].Fichier_Log,name);
		else	
			Fichier_Log = g_strdup (Liste_Categorie[Categorie].Fichier_Log);
		
	
		if (Liste_Categorie[Categorie].deja_ouvert)
			Donnee_Cle->ID_Fichier_Log = open(Fichier_Log, O_WRONLY | O_CREAT | O_APPEND , 0644);
		else
			Donnee_Cle->ID_Fichier_Log = open(Fichier_Log, O_WRONLY | O_CREAT | O_TRUNC , 0644);
		if (Donnee_Cle->ID_Fichier_Log<0){
			printf("ERROR : Create log  (open)  %s\n",Liste_Categorie[Categorie].Fichier_Log);
			DEPROTECT_CODE(Semaphore_Log_File);
			return NULL;
		}
		if (name == NULL)
			Liste_Categorie[Categorie].deja_ouvert = TRUE; 
		MYFREE(Fichier_Log);
	}
	else {
	
		Donnee_Cle->ID_Fichier_Log = Liste_Categorie[Categorie].ID_Fichier_Log;
	}

	if (name == NULL)
		Liste_Categorie[Categorie].used++;
	
	if (Attache_Thread)
		pthread_setspecific(Cle_privee_thread,Donnee_Cle);
	DEPROTECT_CODE(Semaphore_Log_File);
	
	Log_free(Donnee_Cle,g_strdup_printf("---------------------------------------\n------- %s ------\n---------------------------------------\n\n\n",Liste_Categorie[Categorie].Info));
	return Donnee_Cle;
#endif
}


void Close_Log_Thread (struct struct_Cle_Privee *Donnee_Cle){
#ifdef __LOG_ENABLE
	ERROR_if(Donnee_Cle == NULL);
	ERROR_if(Liste_Categorie[Donnee_Cle->Categorie].used <= 0);
	PROTECT_CODE(Semaphore_Log_File);
	switch (Donnee_Cle->Categorie) {
		case CATEG_THREAD_SCAN :// toujours fermer le fichier si c'est le thread du scan d'equipement
				
				if (Donnee_Cle->ID_Fichier_Log==0) {
					printf("Error : close (%s)\n",Liste_Categorie[Donnee_Cle->Categorie].Fichier_Log);
					DEPROTECT_CODE(Semaphore_Log_File);
					return;
				}
				close(Donnee_Cle->ID_Fichier_Log);
				Donnee_Cle->ID_Fichier_Log = 0;
			
				Liste_Categorie[Donnee_Cle->Categorie].used--;
				break;
		default :
				if (Liste_Categorie[Donnee_Cle->Categorie].used == 1) { 
					
					if (Donnee_Cle->ID_Fichier_Log==0) {
						printf("Error : close (%s)\n",Liste_Categorie[Donnee_Cle->Categorie].Fichier_Log);
						DEPROTECT_CODE(Semaphore_Log_File);
						return;
					}
					close(Donnee_Cle->ID_Fichier_Log);		
					Donnee_Cle->ID_Fichier_Log = 0;
					Liste_Categorie[Donnee_Cle->Categorie].ID_Fichier_Log = -1;
				
				}
			
			
				Liste_Categorie[Donnee_Cle->Categorie].used--;					
	}
	DEPROTECT_CODE(Semaphore_Log_File);
#endif
}




void Create_Log_Equipement (struct Struct_Liste_Equipement *Equipement){
#ifdef __LOG_ENABLE
	ERROR_if(Equipement == NULL);
	PROTECT_CODE(Semaphore_Log_File);
	gchar	*Entete;
	
	
	if (Equipement->Fichier_Log == NULL){ 
		Equipement->Fichier_Log = g_strdup_printf(Liste_Categorie[CATEG_THREAD_SCAN].Fichier_Log,Equipement->Adresse_MAC_Char);
		Equipement->ID_Fichier_Log = open(Equipement->Fichier_Log, O_WRONLY | O_CREAT | O_TRUNC , 0644);
	}
	else {
		Equipement->ID_Fichier_Log = open(Equipement->Fichier_Log, O_WRONLY | O_CREAT | O_APPEND , 0644);
	}
	if (Equipement->ID_Fichier_Log < 0){
		printf("ERROR : Create log  (open)  %s\n",Equipement->Fichier_Log);
		DEPROTECT_CODE(Semaphore_Log_File);
		return NULL;
	}
	Liste_Categorie[CATEG_THREAD_SCAN].used++;
	DEPROTECT_CODE(Semaphore_Log_File);
	
	Log_Equipement(Equipement,"--------------------------------\n");
	Log_Equipement(Equipement,Equipement->Adresse_Ip_Char);
	Log_Equipement(Equipement,"\n");
	Log_Equipement(Equipement,Equipement->Adresse_MAC_Char);
	Log_Equipement(Equipement,"\n--------------------------------\n");
#endif
}


void Log_Equipement (struct Struct_Liste_Equipement *Equipement, gchar * Log)
{
#ifdef __LOG_ENABLE
	ERROR_if(Equipement == NULL);
	ERROR_if(Log == NULL);
	PROTECT_CODE(Semaphore_Log_File);
	gint Taille_Chaine;
	
	if (Equipement->ID_Fichier_Log > 0){
		Taille_Chaine = strlen(Log);
		if (Taille_Chaine!=write(Equipement->ID_Fichier_Log,Log,Taille_Chaine)){
			printf("ERROR : Create log  (write)\n");
			DEPROTECT_CODE(Semaphore_Log_File);
			exit (-1);
		}
	}
	DEPROTECT_CODE(Semaphore_Log_File);
#endif
}



void Ckeck_Fermeture_Log (){
#ifdef __LOG_ENABLE
	gint i;
	
	for (i=0;i<NB_CATEGORIE_DEBUG;i++)
		if (Liste_Categorie[i].used!=0)
				printf("ERROR : Close log [%s]\n",Liste_Categorie[i].Info);
#endif
}


void Close_Log_Main(){
#ifdef __LOG_ENABLE
	Close_Log_Thread(Donnee_Cle_Main);
#endif
}


void Initialisation_Repertoire_Log(){
#ifdef __LOG_ENABLE
	DIR      *dir = NULL;
	
	
	dir = opendir (REPERTOIRE_LOG);
	if (dir == NULL) {
	
		if (mkdir (REPERTOIRE_LOG, 0766) != 0) {
			printf("ERROR : Save log  (mkdir)\n");
			exit (-1);
		}
		dir = opendir (REPERTOIRE_LOG);
		if (dir == NULL) {
			printf("ERROR : Save log  (opendir)\n");
			exit (-1);
		}
	}
	closedir (dir);
	
	dir = opendir (REPERTOIRE_LOG_EQUIPEMENT);
	if (dir == NULL) {
	
		if (mkdir (REPERTOIRE_LOG_EQUIPEMENT, 0766) != 0) {
			printf("ERROR : Save log  (mkdir)\n");
			exit (-1);
		}
		dir = opendir (REPERTOIRE_LOG_EQUIPEMENT);
		if (dir == NULL) {
			printf("ERROR : Save log  (opendir)\n");
			exit (-1);
		}
	}
	closedir (dir);
#endif
}


void Initialisation_Log (void)
{

	init_backtrace();
	once_cle_privee = PTHREAD_ONCE_INIT;

	Donnee_Cle_Main = Create_Log(CATEG_MAIN,NULL,NULL,TRUE);
}

#endif  


void Envoie_Log_Equipement (gpointer * Donnee)
{
	struct struct_Demande_Log_Equipement *Message = (struct struct_Demande_Log_Equipement *) Donnee;
	struct struct_Retour_Log_Equipement Message_Retour;
	struct Struct_Liste_Equipement *Equipement = NULL;
	gint      ID_Equipement, Nb_Log, Nb_Caract_Info, Log,Taille_Fichier,A_Lire;
	FILE *fd;
	gchar    *Info_Log = NULL,*line[BUFSIZ];

	ERROR_if (Donnee == NULL);
#ifdef __LOG_ENABLE
	Recherche_Index_Equipement (Message->ID_Equipement, FALSE, &ID_Equipement);
	Retour_Pointeur_Equipement (&Equipement,ID_Equipement);

	bzero (&Message_Retour, sizeof (struct struct_Retour_Log_Equipement));
	Message_Retour.ID_Reseau = Info_Demarrage.ID_Reseau;
	memcpy (Message_Retour.ID_Equipement, Equipement->ID_Equipement, MAC_ADDR_LEN + IP_ADDR_LEN + 1);
	strcpy (Message_Retour.Info, "");

	if ((fd=fopen(Equipement->Fichier_Log,"r+")) == NULL){
		strcat (Message_Retour.Info, "Impossible d'ouvrir le fichier log de l'equipement\n");
		Communication_Envoie_Donnee (RETOUR_LOG_EQUIPEMENT, (gpointer *) & Message_Retour, sizeof (Message_Retour));
		return;
	}

	fseek(fd,0,SEEK_END);

	Taille_Fichier = ftell(fd);

	if (Taille_Fichier<=TAILLE_INFO_LOG_EQUIPEMENT){
		fseek(fd,0,SEEK_SET);
		A_Lire = Taille_Fichier;
	}
	else {
		fseek(fd,Taille_Fichier-TAILLE_INFO_LOG_EQUIPEMENT,SEEK_SET);
		A_Lire = TAILLE_INFO_LOG_EQUIPEMENT;
	}
	while (fgets(line,A_Lire,fd)){
		strcat (Message_Retour.Info, line);
	}
	fclose(fd);
	Communication_Envoie_Donnee (RETOUR_LOG_EQUIPEMENT, (gpointer *) & Message_Retour, sizeof (Message_Retour));
#endif
}
