/* ***********************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 <errno.h>
#include "Notification_Port.h"
#include "Debug.h"
#include "Semaphore.h"
#include "Scan_Port.h"
#include "Com/Initialisation_Com.h"
#include "Com/Commun.h"
#include "Macro.h"

void Thread_Notification_Port (void)
{
	struct Struct_Port *Port = NULL;
	struct Struct_Liste_Equipement *Equipement = NULL;
	struct Struct_Liste_Notification_Port *Notification_Port = NULL;
	struct struct_Retour_Notification_Changement_Etat_Port Message;
	gint      Nb_Objet_Liste, i;
	
#ifdef __LOG_ENABLE
	Create_Log(CATEG_THREAD_NOTIF_PORT,NULL,NULL,TRUE);
#endif
#ifndef         __WINDOWS_ENABLE
	struct sockaddr sock;
	gint	Socket;
	
	strcpy (sock.sa_data, Info_Demarrage.Interface);
	sock.sa_family = AF_INET;
	if ((Socket = socket_control (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0)
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s\nSocket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)", strerror (errno), Nb_Socket_Ouverte, Info_Demarrage.Nb_Thread_Max, Info_Demarrage.Nb_Thread_Max - Valeur_Semaphore (&Semaphore_Thread_Scan), g_list_length (GList_Equipement));
#else
	pcap_t    * captureHandle;
	char errbuf[PCAP_ERRBUF_SIZE];
	 
	if ( (captureHandle = pcap_open(Info_Demarrage.nom, 65535, PCAP_OPENFLAG_PROMISCUOUS, 1, NULL,  errbuf ) ) == NULL)
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Unable to open the adapter. %s is not supported by WinPcap\n", Info_Demarrage.nom);
#endif

	while (TRUE) {
		i = 0;
		Nb_Objet_Liste = g_list_length (GList_Notification_Port);
		while (i < Nb_Objet_Liste) {
		
			PROTECT_CODE(Semaphore_Notification_Port);

			Nb_Objet_Liste = g_list_length (GList_Notification_Port);
			if (i < Nb_Objet_Liste) {
				Notification_Port = g_list_nth_data (GList_Notification_Port, i);
				Equipement = Notification_Port->Equipement;
				Port = Notification_Port->Port;
				if ((!Equipement->Scan_Port_En_Cours)&& (Equipement->ID_Equipement[6] != 0)) { 
					if (Port->Compteur_Notification < TEMP_NOTIFICATION_PORT_CRITIQUE) {
						if (Port->Compteur_Notification >= TEMP_NOTIFICATION_PORT_CRITIQUE / 2)
#ifndef         __WINDOWS_ENABLE
							Envoie_Trame_Scan_Port (Equipement, Port->Num_Port, Socket, &sock,NULL);
#else
							Envoie_Trame_Scan_Port (Equipement, Port->Num_Port, captureHandle,NULL);
#endif
						Port->Compteur_Notification++;
					}
					if (Port->Compteur_Notification == TEMP_NOTIFICATION_PORT_CRITIQUE) {
						Port->Compteur_Notification = 0;;
						Port->Etat_Port = FERMER;
						if (!Port->Alerte_Port_Active) {
							bzero (&Message, sizeof (struct struct_Retour_Notification_Changement_Etat_Port));
							Message.ID_Reseau = Info_Demarrage.ID_Reseau;
							memcpy (Message.ID_Equipement, Equipement->ID_Equipement, MAC_ADDR_LEN + IP_ADDR_LEN + 1);
							Message.Num_Port = Port->Num_Port;
							Communication_Envoie_Donnee (RETOUR_NOTIFICATION_CHANGEMENT_ETAT_PORT, (gpointer *) & Message, sizeof (Message));
						}
						Port->Alerte_Port_Active = TRUE;
					}
				}
			}
			DEPROTECT_CODE(Semaphore_Notification_Port);
			i++;
		}
		sleep (1);
	}
}

void Ajout_Notification_Port (gpointer * Donnee)
{
	struct struct_Demande_Notication_Critique_Etat_Port *Message = (struct struct_Demande_Notication_Critique_Etat_Port *) Donnee;
	struct Struct_Liste_Equipement *Equipement = NULL;
	gint      ID_Equipement;

	ERROR_if (Donnee == NULL);
	Recherche_Index_Equipement (Message->ID_Equipement,FALSE, &ID_Equipement);
	if (ID_Equipement == EQUIPEMENT_UNKNOWN) {
		debug_printf (D_WARN_USER, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Add (Equipment unknown)");
		return;	
	}
	/*if (ID_Equipement == EQUIPEMENT_NO_IP) {
		debug_printf (D_WARN_USER, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Add (no IP)");
		return;	
	}*/
	Retour_Pointeur_Equipement (&Equipement,ID_Equipement);
	Ajout_Notification_Port_Glist (Equipement, Message->Num_Port);
}

void Enlever_Notification_Port (gpointer * Donnee)
{
	struct struct_Annulation_Notification_Etat_Port *Message = (struct struct_Annulation_Notification_Etat_Port *) Donnee;
	struct Struct_Liste_Equipement *Equipement = NULL;
	gint      ID_Equipement;

	ERROR_if (Donnee == NULL);
	Recherche_Index_Equipement (Message->ID_Equipement,TRUE, &ID_Equipement);
	if (ID_Equipement == EQUIPEMENT_UNKNOWN) {
		debug_printf (D_WARN_USER, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Delete (Equipment unknown)");
		return;	
	}
	if (ID_Equipement == EQUIPEMENT_NO_IP) {
		debug_printf (D_WARN_USER, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Delete (no IP)");
		return;	
	}
	Retour_Pointeur_Equipement (&Equipement,ID_Equipement);
	Enlever_Notification_Port_Glist (Equipement, Message->Num_Port);
}

void Affiche_Debug_Liste_Notification_Port_Securiser (void)
{
	PROTECT_CODE(Semaphore_Notification_Port);
	struct Struct_Liste_Notification_Port *Notification_Port = NULL;
	gint      Nb_Objet_Liste, i;

	Nb_Objet_Liste = g_list_length (GList_Notification_Port);
	for (i = 0; i < Nb_Objet_Liste; i++)
		Notification_Port = g_list_nth_data (GList_Notification_Port, i);
	DEPROTECT_CODE(Semaphore_Notification_Port);
}

struct Struct_Port *Recupere_Pointeur_Notification_Port_Dans_Une_Liste (int rang)
{
	return g_list_nth_data (GList_Notification_Port, rang);
}

gint Recherche_Index_Notification_Port_Non_Securiser (struct Struct_Liste_Equipement * Equipement, gint Num_Port)
{
	struct Struct_Liste_Notification_Port *Notification_Port = NULL;
	gint      Nb_Objet_Liste, i;

	ERROR_if (Equipement == NULL);
	Nb_Objet_Liste = g_list_length (GList_Notification_Port);
	for (i = 0; i < Nb_Objet_Liste; i++) {
		Notification_Port = g_list_nth_data (GList_Notification_Port, i);
		if ((Notification_Port->Equipement == Equipement) && (Notification_Port->Num_Port == Num_Port))
			return i;
	}
	return -1;	
}

void Enlever_Notification_Port_Glist (struct Struct_Liste_Equipement *Equipement, gint Num_Port)
{
	ERROR_if (Equipement == NULL);
	PROTECT_CODE(Semaphore_Notification_Port);
	struct Struct_Port *Port_Equipement = NULL;
	gint      ID_Port;

	Port_Equipement = Recupere_Pointeur_Port_Glist (Equipement, Num_Port);
	if (Port_Equipement != NULL) {
		Port_Equipement->Notification = FALSE;
		if ((ID_Port = Recherche_Index_Notification_Port_Non_Securiser (Equipement, Num_Port)) != -1)
			G_LIST_REMOVE(GList_Notification_Port, Recupere_Pointeur_Notification_Port_Dans_Une_Liste (ID_Port));
		else
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Enlever Notification Port n'existe pas: [%s]:[%d]", Equipement->Adresse_MAC_Char, Num_Port);
	}
	DEPROTECT_CODE(Semaphore_Notification_Port);
	Affiche_Debug_Liste_Notification_Port_Securiser ();
}

void Ajout_Notification_Port_Glist (struct Struct_Liste_Equipement *Equipement, gint Num_Port)
{
	ERROR_if (Equipement == NULL);
	PROTECT_CODE(Semaphore_Notification_Port);
	struct Struct_Liste_Notification_Port *Notification_Port = NULL;
	struct Struct_Port *Port_Equipement = NULL;

	Port_Equipement = Recupere_Pointeur_Port_Glist (Equipement, Num_Port);
	if (Port_Equipement != NULL) {
		Port_Equipement->Notification = TRUE;
		if (Recherche_Index_Notification_Port_Non_Securiser (Equipement, Num_Port) == -1) {
			MALLOC(Notification_Port,sizeof (struct Struct_Liste_Notification_Port));
			Notification_Port->Equipement = Equipement;
			Notification_Port->Num_Port = Num_Port;
			Notification_Port->Port = Port_Equipement;
			G_LIST_APPEND (GList_Notification_Port, Notification_Port);
		}
		else
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Nouveau Notification Port existe deja : %s [%s] Port(%d)", Notification_Port->Equipement->Adresse_Ip_Char, Notification_Port->Equipement->Adresse_MAC_Char, Num_Port);
	}
	DEPROTECT_CODE(Semaphore_Notification_Port);
	Affiche_Debug_Liste_Notification_Port_Securiser ();
}


void Initialisation_Notification_Port (void)
{
	GList_Notification_Port = NULL;
}
