/* ***********************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 <glib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include "Erreur.h"
#include "Debug.h"
#include "Socket.h"
#include "Thread.h"
#include "Semaphore.h"
#include "Com/Initialisation_Com.h"
#include "Declaration_Constante.h"
#include "Quit.h"
#include "Macro.h"

#ifdef __LOG_ENABLE
extern struct Struct_Categorie Liste_Categorie[];
#endif


#ifdef __LOG_ENABLE
void Message_Erreur_Critique (struct struct_Cle_Privee *pCle, gint Type_message)
{
	struct Struct_Liste_Equipement *Equipement;
	struct struct_Retour_Erreur_Critique Message_Critique;
	GList    *GList_Log = NULL;
	gchar    *Info_Log = NULL,*line[BUFSIZ], *chemin=NULL;
	gint      Nb_Log, Nb_Caract_Info, Log,Taille_Fichier,A_Lire;
	FILE *fd;
	
	if (Demarrage_Complet_Agent) {
	
		bzero (&Message_Critique, sizeof (struct struct_Retour_Erreur_Critique));
		Message_Critique.ID_Reseau = Info_Demarrage.ID_Reseau;
		Message_Critique.Type_message = Type_message;
				
		if (pCle == NULL) {
			strcpy (Message_Critique.Thread, "??");
			strcpy (Message_Critique.Objet, "??");
			strcpy (Message_Critique.Info, "??");
		}
		else {
			strcpy (Message_Critique.Thread, Liste_Categorie[pCle->Categorie].Info);
			strcpy (Message_Critique.Objet, "none");
			switch (pCle->Categorie) {
			    case CATEG_THREAD_SCAN:
				    Equipement = pCle->Pointeur_Data;
				    strcpy (Message_Critique.Objet, Equipement->Adresse_Ip_Char);
				    break;
			    case CATEG_NESSUS:
				    Equipement = pCle->Pointeur_Data;
				    strcpy (Message_Critique.Objet, Equipement->Adresse_Ip_Char);
				    break;
			    case CATEG_THREAD_SNMP_LISTE_ALL:
				    Equipement = pCle->Pointeur_Data;
				    strcpy (Message_Critique.Objet, Equipement->Adresse_Ip_Char);
				    break;
			    case CATEG_THREAD_SNMP_LISTE:
				    Equipement = pCle->Pointeur_Data;
				    strcpy (Message_Critique.Objet, Equipement->Adresse_Ip_Char);
				    break;
				case CATEG_THREAD_SNMP_SCALAIRE:
				    Equipement = pCle->Pointeur_Data;
				    strcpy (Message_Critique.Objet, Equipement->Adresse_Ip_Char);
				    break;
			}
			
		
			if (pCle->Categorie == CATEG_THREAD_SCAN)
				chemin = g_strdup_printf(Liste_Categorie[CATEG_THREAD_SCAN].Fichier_Log,Equipement->Adresse_MAC_Char);
			else 
				chemin = g_strdup(Liste_Categorie[pCle->Categorie].Fichier_Log);
		
			if ((fd=fopen(chemin,"r+")) == NULL){
				strcat (Message_Critique.Info, "Impossible d'ouvrir le fichier log : ");
				strcat (Message_Critique.Info, chemin);
				Communication_Envoie_Donnee (RETOUR_ERREUR_CRITIQUE, (gpointer *) & Message_Critique, sizeof (Message_Critique));
				MYFREE(chemin);
				return;
			}
			MYFREE(chemin);
		
			fseek(fd,0,SEEK_END);
		
			Taille_Fichier = ftell(fd);
		
			if (Taille_Fichier<=TAILLE_INFO_ERREUR_CRITIQUE){
				fseek(fd,0,SEEK_SET);
				A_Lire = Taille_Fichier;
			}
			else {
				fseek(fd,Taille_Fichier-TAILLE_INFO_ERREUR_CRITIQUE,SEEK_SET);
				A_Lire = TAILLE_INFO_ERREUR_CRITIQUE;
			}
			while (fgets(line,A_Lire,fd)){
				strcat (Message_Critique.Info, line);
			}
			fclose(fd);
			
			
		
			/*Nb_Log = g_list_length (GList_Log);
			Log = Nb_Log;
			strcpy (Message_Critique.Info, "");
			Nb_Caract_Info = 0;
			while ((Log > 1) && (Log + 100 != Nb_Log) && (Nb_Caract_Info < TAILLE_INFO_ERREUR_CRITIQUE)) {
				Info_Log = g_list_nth_data (GList_Log, Log - 1);
				if ((strlen (Info_Log) + Nb_Caract_Info) > TAILLE_INFO_ERREUR_CRITIQUE)
					break;
				strcat (Message_Critique.Info, Info_Log);
				strcat (Message_Critique.Info, "\n");
				Nb_Caract_Info = Nb_Caract_Info + strlen (Info_Log) + 2;
				Log--;
			}*/
		}
		Communication_Envoie_Donnee (RETOUR_ERREUR_CRITIQUE, (gpointer *) & Message_Critique, sizeof (Message_Critique));
	}
}
#endif



#ifndef         __WINDOWS_ENABLE

void segfault_handler (int sig)
{	
	struct Struct_Liste_Equipement* Equipement = NULL;
	struct struct_Cle_Privee *pCle = NULL;
	
	printf("SegFault\n");
	signal (SIGSEGV, Arret_Immediat);

	if ((pCle = pthread_getspecific (Cle_privee_thread)) == NULL)
		pCle = Donnee_Cle_Main;

	if (pCle->Categorie==CATEG_THREAD_SCAN)
		Equipement = pCle->Pointeur_Data;
	printf ("Segfault : Invalid memory reference (%s)\n", Liste_Categorie[pCle->Categorie].Info);

	display_backtrace(NULL,NULL,0);

	Log (pCle, "#####################################\n");
	Log (pCle, "---------- Segfault(Agent) ----------\n");
	display_backtrace (pCle,NULL,0);
	printf ("Stopping %s (http://autoscan-network.com)\n", VERSION_AGENT);
	Message_Erreur_Critique(pCle,D_SEG_FAULT);
	Close_Log_Main();	
	Ckeck_Fermeture_Log(); 
	exit(EXIT_SUCCESS);	
}

void Control_C (int sig)
{
	printf ("Control_C\n");
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Arret (Control_C) Socket ouvert[%d]  Thread[%d]", Nb_Socket_Ouverte, Info_Demarrage.Nb_Thread_Max - Valeur_Semaphore (&Semaphore_Thread_Scan));
	Arret_Demande (NULL);
}


void Initialisation_Signal_Erreur (void)
{
 struct sigaction    sa;
 sigset_t            sigmsk;

 
	sigfillset( &sigmsk );
    sigdelset( &sigmsk, SIGUSR1 );
	sigdelset( &sigmsk, SIGUSR2 );
    sigdelset( &sigmsk, SIGHUP );
    sigdelset( &sigmsk, SIGWINCH );
    sigdelset( &sigmsk, SIGINT );
    sigdelset( &sigmsk, SIGSEGV );
    sigdelset( &sigmsk, SIGILL );
    sigdelset( &sigmsk, SIGFPE );
    pthread_sigmask( SIG_SETMASK, &sigmsk, NULL );

 
    sa.sa_sigaction = Pause_Thread;
    sigemptyset( &sa.sa_mask );
    sa.sa_flags = SA_RESTART;
    sigaction( SIGUSR1, &sa, NULL );
	
	signal (SIGSEGV, segfault_handler);
	signal (SIGINT, Control_C);
}
#endif
