/* ***********************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 "Scan_Netbios.h"
#include "Debug.h"
#include "Info.h"
#include "Reseau.h"
#include "Macro.h"

char      nbtname[] = { 0x80, 0xf0, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21, 0x00, 0x01 };

#define MAX_NAME_SIZE 16
gchar *get_nbns_name(unsigned char *Datagramme){
	gchar  cname_a,cname_b,result;
	gchar  *Name;
	gint i;

	ERROR_if (Datagramme == NULL);
	i = 0;
	MALLOC(Name,sizeof(gchar)*MAX_NAME_SIZE);
	result = '?';
	while ((i<(MAX_NAME_SIZE -1)) && (result!=' ')){ 
		cname_a = (Datagramme[(i*2)+1] - 'A') & 0x0F;
		cname_b = (Datagramme[(i*2)+2] - 'A') & 0x0F;
		result = cname_a << 4 | cname_b;
	
		if (result < ' ' || result > 127)
			result = '?';
		if (result == ' ')
			Name[i] = 0;
		else
			Name[i] = result;
		i++;
	}
	Name[MAX_NAME_SIZE -1] = 0;
	return Name;
}
	

void Change_Name_Netbios(struct Struct_Liste_Equipement *Equipement,gchar *Utilisateur){
	struct struct_Retour_Rafraichir_Nom_Utilisateur Message;
		
	ERROR_if (Equipement == NULL);
	ERROR_if (Utilisateur == NULL);	
	strcpy(Equipement->Smb.Utilisateur,Utilisateur);
	bzero (&Message, sizeof (struct struct_Retour_Rafraichir_Nom_Utilisateur));
	Message.ID_Reseau = Info_Demarrage.ID_Reseau;
	memcpy (Message.ID_Equipement, Equipement->ID_Equipement, MAC_ADDR_LEN + IP_ADDR_LEN + 1);
	strcpy(Message.Utilisateur,Utilisateur);
	Communication_Envoie_Donnee (RETOUR_RAFRAICHIR_NOM_UTILISATEUR, (gpointer *) & Message, sizeof (Message));
	MYFREE(Utilisateur);
}



void waiting_donnee (struct Struct_Liste_Equipement * Equip,int sock, int pause)
{
	ERROR_if (Equip == NULL);
#ifndef         __WINDOWS_ENABLE
	fd_set fd_read,fd_write;
	socklen_t lon; 
    struct timeval tv;
	int retval,valopt,NbSeconde; 
	
	NbSeconde = 0;
	while (NbSeconde<3){
	
	
	
		FD_ZERO(&fd_read);
		FD_SET(sock, &fd_read);
		FD_ZERO(&fd_write);
		FD_SET(sock, &fd_write);
	
   		tv.tv_sec = 1;
    	tv.tv_usec = 0;
 		retval = select(sock + 1,&fd_read, &fd_write, NULL, &tv);
    	if (retval==2){
		
    		lon = sizeof(int); 
    		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
				debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); 
	       		Equip->Resultat_waiting_donnee = FALSE;
				return;
			} 
			if (valopt) { 
				debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Error in delayed connection() %d - %s",valopt, strerror(valopt)); 
				Equip->Resultat_waiting_donnee = FALSE;
				return;
			} 
			debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Donnee presente sur la socket (%d)",sock);
			Equip->Resultat_waiting_donnee = TRUE;
			return;
		}
    	else {
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Aucune donnée depuis 1 secondes  retval=%d",retval);
			sleep(1);
		}
	
		NbSeconde++;
	}
	Equip->Resultat_waiting_donnee = FALSE;
	return;
	
	/*bzero (&Equip->fds, sizeof(struct pollfd));
	Equip->fds.events = POLLIN;
	Equip->fds.fd = sock;	
	if ((Equip->resultat = poll (&Equip->fds, 1, pause)) > 0) {
		if ((Equip->fds.revents & POLLERR) == POLLERR) {
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Condition d'erreur");
			Equip->Resultat_waiting_donnee = FALSE;
			return;
		}
		if ((Equip->fds.revents & POLLHUP) == POLLHUP) {
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Déconnexion");
			Equip->Resultat_waiting_donnee = FALSE;
			return;
		}
		Equip->Resultat_waiting_donnee = TRUE;
		return;
	}
	else {
		if (Equip->resultat != 0)
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s", strerror (errno));
		Equip->Resultat_waiting_donnee = FALSE;
		return;
	}*/
#else
	Equip->NbSeconde = 0;
	while (Equip->NbSeconde<3){
		FD_ZERO(&Equip->ensemble);
		FD_SET(sock, &Equip->ensemble);
		
		Equip->tv.tv_sec = 1;
   		Equip->tv.tv_usec = 0;
 		Equip->retval = select(sock + 1, &Equip->ensemble , NULL , NULL, &Equip->tv);
   		 if (Equip->retval){
       		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Données disponibles maintenant sur socket : %d\n",sock);
			Equip->Resultat_waiting_donnee = TRUE;
			return;
		}
    	else{
			debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Pas de données depuis 1 secondes\n");
			Equip->NbSeconde++;
		}
	}
	Equip->Resultat_waiting_donnee = FALSE;
	return;
#endif
}


void Demande_NetBios (struct Struct_Liste_Equipement * Equip, gint Tentative)
{
	ERROR_if (Equip == NULL);
	usleep (SURCHARGE_EQUIPEMENT);	
	Equip->FinChaine = NULL;
	Equip->sockaddr_in_len = sizeof(struct sockaddr_in);	
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "tentative %d",Tentative);

	if ((Equip->Socket_Netbios = socket_control(PF_INET, SOCK_DGRAM, 0)) < 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));

	bzero (&Equip->Smb, sizeof (struct struct_Smb));

	bzero ((char *) &Equip->SockName, sizeof (struct sockaddr_in));
	if (inet_aton(Equip->Adresse_Ip_Char,&Equip->SockName.sin_addr)==0)
			debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "inet_aton()");
	Equip->SockName.sin_family = AF_INET;
	Equip->SockName.sin_port = htons (NETBIOS);

	Nouveau_Octet_Envoye (sizeof (nbtname));
	if (sendto (Equip->Socket_Netbios, nbtname, sizeof (nbtname), 0, (struct sockaddr *) &Equip->SockName, Equip->sockaddr_in_len) < 0) {
		if ((errno != EPIPE) && (errno != ESPIPE))
			debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s",strerror (errno));
	}
	else {
		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Demande NETBIOS tentative (%d)[%s]", Tentative, Equip->Adresse_Ip_Char);
		waiting_donnee (Equip,Equip->Socket_Netbios, 3000);
		if (Equip->Resultat_waiting_donnee) {
			Equip->octet_recu = recvfrom (Equip->Socket_Netbios, Equip->buf, TAILLE_BUFFER_NETBIOS - 1, 0, (struct sockaddr *) &Equip->SockName, &Equip->sockaddr_in_len);
			if (Equip->octet_recu==-1){
				debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] Socket %d : %s", Equip->Adresse_Ip_Char,Equip->Socket_Netbios, strerror (errno));
				if (close_control (Equip->Socket_Netbios) < 0)
#ifndef         __WINDOWS_ENABLE
					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
					debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Erreur(%d)  %s\nSocket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)",WSAGetLastError(), 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));
#endif
				Equip->Resultat_Netbios = FALSE;	
				return;
			}
			Nouveau_Octet_Recu (Equip->octet_recu);
			if (Equip->buf[56] == 0) {
				if (close_control (Equip->Socket_Netbios) < 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));
				Equip->Resultat_Netbios = TRUE;
				return;
			}
			for (Equip->i = 0; Equip->i < Equip->buf[56]; Equip->i++) {
				strncpy (Equip->Smb.Smb_Registration[Equip->i].Name, &Equip->buf[57 + (Equip->i * 18)], 15);
				Equip->Smb.Smb_Registration[Equip->i].Name[15] = 0;
				Equip->j = 14;
				while ((Equip->j != 0) && (Equip->Smb.Smb_Registration[Equip->i].Name[Equip->j] == 0x20)) {
					Equip->Smb.Smb_Registration[Equip->i].Name[Equip->j] = 0;
					Equip->j--;
				}
				for (Equip->j = 0; Equip->j < strlen (Equip->Smb.Smb_Registration[Equip->i].Name); Equip->j++)
					if (Equip->Smb.Smb_Registration[Equip->i].Name[Equip->j] < 31 || Equip->Smb.Smb_Registration[Equip->i].Name[Equip->j] > 126)
						Equip->Smb.Smb_Registration[Equip->i].Name[Equip->j] = '_';
			
				Equip->Smb.Smb_Registration[Equip->i].Numero = Equip->buf[57 + 15 + (Equip->i * 18)];
			
				if (Equip->buf[57 + 15 + 1 + (Equip->i * 18)] & 128) {
					Equip->Smb.Smb_Registration[Equip->i].Type = REGISTRATION_GROUP;
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "GROUP %s <%02X>", Equip->Adresse_Ip_Char, Equip->Smb.Smb_Registration[Equip->i].Name, Equip->Smb.Smb_Registration[Equip->i].Numero);
				}
				else {
					Equip->Smb.Smb_Registration[Equip->i].Type = REGISTRATION_UNIQUE;
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "UNIQUE   %s <%02X>", Equip->Adresse_Ip_Char, Equip->Smb.Smb_Registration[Equip->i].Name, Equip->Smb.Smb_Registration[Equip->i].Numero);
				}
				if ((Equip->Smb.Smb_Registration[Equip->i].Numero == 0x20) && (Equip->Smb.Smb_Registration[Equip->i].Type = REGISTRATION_UNIQUE))
					strcpy (Equip->Smb.HostName, Equip->Smb.Smb_Registration[Equip->i].Name);
			
				if ((Equip->Smb.Smb_Registration[Equip->i].Numero == 0x00) && (Equip->Smb.Smb_Registration[Equip->i].Type == REGISTRATION_GROUP))
					strcpy (Equip->Smb.DomainName, Equip->Smb.Smb_Registration[Equip->i].Name);
			
				if ((Equip->Smb.Smb_Registration[Equip->i].Numero == 0x03) && (Equip->Smb.Smb_Registration[Equip->i].Type == REGISTRATION_UNIQUE))
					strcpy (Equip->Smb.Utilisateur, Equip->Smb.Smb_Registration[Equip->i].Name);
			}
		}
		else {
			if (close_control (Equip->Socket_Netbios) < 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));
			debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Aucune reponse NETBIOS tentatice(%d) (%s)", Equip->Tentative, Equip->Adresse_Ip_Char);
			Equip->Resultat_Netbios = FALSE;
			return;
		}
	}
	if (close_control (Equip->Socket_Netbios) < 0)
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s\n[%s] Socket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)", Equip->Adresse_Ip_Char,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));
	Equip->Resultat_Netbios = TRUE;
	return;
}
