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

void Recupere_Nom_DNS (struct Struct_Liste_Equipement *Equip)
{
	ERROR_if (Equip->Adresse_Ip_Char == NULL);
	PROTECT_CODE (Semaphore_DNS);
	
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Recupere_Nom_DNS = [%s]",Equip->Adresse_Ip_Char);
	Equip->host = NULL;
	Equip->addr = inet_addr ((char *) Equip->Adresse_Ip_Char);
	Equip->host = gethostbyaddr((char *)&Equip->addr, sizeof(struct in_addr),AF_INET);
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Fin  taille [%d] herr : %d   Erreur : %d",Equip->Taille_Buffer,Equip->herr,Equip->erreur);
	
	if (Equip->host == NULL) {
#ifndef         __WINDOWS_ENABLE
		switch (h_errno) {
		    case HOST_NOT_FOUND:
			    debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "L'hôte indiqué est inconnu.(%s) [%s]", hstrerror (Equip->herr), Equip->Adresse_Ip_Char);
			    break;
		    case NO_ADDRESS:
			    debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Le nom est valide mais ne possède pas d'adresse IP.(%s) [%s]", hstrerror (Equip->herr), Equip->Adresse_Ip_Char);
			    break;
		    case NO_RECOVERY:
			    debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Une erreur fatale du serveur de noms est apparue.(%s) [%s]", hstrerror (Equip->herr), Equip->Adresse_Ip_Char);
			    break;
		    case TRY_AGAIN:
			    debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Aucune connection à  internet.(%s) [%s]", hstrerror (Equip->herr), Equip->Adresse_Ip_Char);
			    break;
		    default:
			    debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Erreur Inconnue(%d) pour [%s]", Equip->herr, Equip->Adresse_Ip_Char);
			    break;
		}
#else
		debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Dns Failed.[%s]",Equip->Adresse_Ip_Char);
#endif
		Equip->M->Nom_DNS[0] = 0 ;
	}
	else {
		Equip->Taille_Chaine = strlen (Equip->host->h_name);
		if (Equip->Taille_Chaine != 0) {
			if (Equip->Taille_Chaine > TAILLE_CHAINE_NOM_DNS)
				Equip->Taille_Chaine = TAILLE_CHAINE_NOM_DNS;
			strncpy (Equip->M->Nom_DNS, Equip->host->h_name, Equip->Taille_Chaine);
			Equip->M->Nom_DNS[Equip->Taille_Chaine] = 0;
			debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Nom DNS = [%s]", Equip->M->Nom_DNS);
		}
	}
	DEPROTECT_CODE (Semaphore_DNS);
}

gchar *connect_service(struct Struct_Liste_Equipement *Equipement,gchar *Protocol,int Port){
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Connect to %s  [%s]",Protocol, Equipement->Adresse_Ip_Char);
	if ((Equipement->IdSocket = Connection_Equipement (Equipement->Adresse_Ip_Char, NULL, Port, Time_Out_Connect_Service, 0,FALSE)) == -1) {
		debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Connexion refusée au serveur %s [%s]",Protocol, Equipement->Adresse_Ip_Char);
		return g_strdup_printf ("[Error] %s: Connection refused",Protocol);
	}
	return NULL;
}

gchar *send_service(struct Struct_Liste_Equipement *Equip,gchar *Requete,gint Taille_Requete,gchar *Protocol){
	int 	  Tentative,NbOctet;
	
	ERROR_if (Equip == NULL);
	ERROR_if (Equip->Requete == NULL);
	ERROR_if (Protocol == NULL);

	if (!attendre_Donnee_Ecriture(Equip->IdSocket, Time_Out_Service))
		return  g_strdup_printf ("[Error] %s : Socket non prete",Protocol);
	Tentative = 0;

	do { 
		Tentative++;
		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] Socket (%d) tentative (%d)",Protocol,Equip->IdSocket,Tentative);
		NbOctet = send (Equip->IdSocket, Requete, Taille_Requete , 0);
		if (NbOctet < 1){
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] NbOctet == %d   %s  Socket (%d)", Protocol, NbOctet,strerror (errno),Equip->IdSocket);
			if (NbOctet == -1){ 
				if (!(errno == EINTR || errno == EAGAIN)){
					if (close_control (Equip->IdSocket) < 0)
						debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] %s\nSocket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)", Protocol, 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));
					return  g_strdup_printf ("[Error] %s : send NbOctet == -1",Protocol);
				}
				sleep(1);
			}
			else
				sleep(1);
		}
		else{
			if (NbOctet != Taille_Requete){
				debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] NbOctet != Taille_Requete [%s]  Socket (%d)", Protocol, strerror (errno),Equip->IdSocket);
				if (close_control (Equip->IdSocket) < 0)
					debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] [%s]\nSocket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)", Protocol, 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));
				return g_strdup_printf ("[Error] %s : NbOctet != Taille_Requete",Protocol);
			}
		}
	} while((Tentative<10) && (NbOctet == -1) && (errno == EAGAIN || errno == EINTR));
	if (NbOctet != Taille_Requete)  {
		debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] %s Socket (%d)",Protocol , strerror (errno),Equip->IdSocket);
		if (close_control (Equip->IdSocket) < 0)
			debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] %s\nSocket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)", Protocol, 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));
		return g_strdup_printf("[Error] %s :  NbOctet != Taille_Requete    CAS IMPOSSIBLE   Tentative(%d)",Protocol,Tentative);
	}
	Nouveau_Octet_Envoye (NbOctet);
	return NULL; 
}

gchar *read_service(struct Struct_Liste_Equipement *Equip,gchar *debut_entete, gchar *chaine_fin_entete,gchar *Protocol,gboolean deuxlignes){
	gchar	  *banniere, buffer[TAILLE_REQUETE_SERVICE],*repere,*repere2;
	int		  tailleBanniere,Tentative,Nb_Error_Consecutive,NbOctet,NbOctetTotal,i,nbLigne,retourLecture;
	gboolean fin;
	

	Tentative = 0; Nb_Error_Consecutive = 0; NbOctetTotal = 0; nbLigne = 0;retourLecture=0;
	fin = FALSE;

	banniere = g_strdup(debut_entete);
	tailleBanniere = strlen(banniere) + 1;

	while ((!fin) && (Tentative!=50) && (Nb_Error_Consecutive<3) && ((retourLecture = attendre_Donnee_Lecture (Equip->IdSocket, Time_Out_Service))>0)) {
		NbOctet = recvfrom (Equip->IdSocket, &buffer, (sizeof(gchar)*TAILLE_REQUETE_SERVICE) - 1 - NbOctetTotal, 0, NULL, 0);
	
		if (NbOctet < 1){ 
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "NbOctet==[%d] Total[%d] %s  Socket (%d) Erreur Consécutive (%d)",NbOctet,NbOctetTotal, strerror (errno),Equip->IdSocket,Nb_Error_Consecutive);
			if (NbOctet == -1){ 
				if (!(errno == EINTR || errno == EAGAIN)){
					if (close_control (Equip->IdSocket) < 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));
					MYFREE(banniere); 
					return g_strdup_printf ("[Error] %s :  NbOctet == -1",Protocol);
				}
				sleep(1);
			}
			else
				sleep(1);
			Nb_Error_Consecutive++;
		}
		else {
		
			buffer[NbOctet] = 0; 
		
			i = 0;
			while ((i<NbOctet) && (buffer[i]!=0)){
				if (((buffer[i]<32) || (buffer[i]>126)) && (buffer[i]!='\r') && (buffer[i]!='\n'))  
					buffer[i] = '_';
				i++;
			}
			if (i!=NbOctet){
				NbOctet = i; 
				debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Caractère final %d %d",NbOctet,i);
			}
		
			NbOctetTotal = NbOctetTotal + NbOctet;
			Nouveau_Octet_Recu (NbOctet);
			if (!deuxlignes){
			
			
				if ((repere = strstr(buffer,chaine_fin_entete))==NULL){
				
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Banniere[%d=%d]A[%d]T[%d]  --> [%s]",strlen(banniere)+1,tailleBanniere,NbOctet,NbOctetTotal,buffer);
					REALLOC(banniere,(sizeof (gchar) * (tailleBanniere + NbOctet)));
					strcat (banniere, buffer);
					tailleBanniere = tailleBanniere + NbOctet;
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "NBanniere[%d=%d]",strlen(banniere)+1,tailleBanniere);
				}
				else {
				
					NbOctet = repere - buffer + 2;
					buffer[NbOctet] = 0;
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "FBanniere[%d=%d] --> [%s] ",strlen(banniere)+1,tailleBanniere,buffer);
					REALLOC(banniere,(sizeof (gchar) * (tailleBanniere + NbOctet)));
					strcat (banniere, buffer);
					tailleBanniere = tailleBanniere + NbOctet;
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "FBanniere[%d=%d]",strlen(banniere)+1,tailleBanniere);
					fin = TRUE;
				}
			}
			else {
			
				if ((repere = strstr(buffer,chaine_fin_entete))==NULL){
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Repere pas trouvé [%d=%d]A[%d]T[%d]  --> [%s]",strlen(banniere)+1,tailleBanniere,NbOctet,NbOctetTotal,buffer);
					REALLOC(banniere,(sizeof (gchar) * (tailleBanniere + NbOctet)));
					strcat (banniere, buffer);
					tailleBanniere = tailleBanniere + NbOctet;
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "NRepere pas trouvé  [%d=%d]",strlen(banniere)+1,tailleBanniere);
				}
				else {
				
					if ((repere2 = strstr(repere + strlen(chaine_fin_entete),chaine_fin_entete))!=NULL){
						debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "2 lignes en un coups");
						nbLigne++;
						repere = repere2;
					}
					nbLigne++;
					NbOctet = repere - buffer + strlen(chaine_fin_entete);
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Repere trouvé : lignes %d  NbOctet(%d)   Taille Futur(%d)  bannière(%d)",nbLigne,NbOctet,(sizeof (gchar) * (tailleBanniere + NbOctet)),tailleBanniere);					
					REALLOC(banniere,(sizeof (gchar) * (tailleBanniere + NbOctet)));
					buffer[NbOctet] = 0;  
					strcat (banniere, buffer);
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Bannière OK : [%d=%d]A[%d]T[%d]  --> [%s]",strlen(banniere)+1,tailleBanniere,NbOctet,NbOctetTotal,buffer);
					tailleBanniere = tailleBanniere + NbOctet;
					if (nbLigne == 2){
						debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Fin des donnees a recuperer (%s)",Protocol);
						fin = TRUE;
					}
				}
			}
			Nb_Error_Consecutive = 0;
		}
		Tentative++;
		retourLecture = 0;
	}

	if ((retourLecture <0) &&(tailleBanniere == (strlen(debut_entete) + 1))){
		MYFREE(banniere); 
		switch (retourLecture){
			case SOCK_BROKEN_PIPE :
					
						NbOctet = recvfrom (Equip->IdSocket, &buffer, (sizeof(gchar)*TAILLE_REQUETE_SERVICE) - 1 - NbOctetTotal, 0, NULL, 0);
					
						if (NbOctet < 1){ 
							return g_strdup_printf("[TcpWrapped] %s : Port %d - %s",Protocol,(-retourLecture), strerror(-retourLecture));
						}
						debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Socket Broken Pipe mais on a des données à recuperer (%s)",Protocol);
					
						buffer[NbOctet] = 0; 
					
						i = 0;
						while ((i<NbOctet) && (buffer[i]!=0)){
							if (((buffer[i]<32) || (buffer[i]>126)) && (buffer[i]!='\r') && (buffer[i]!='\n'))  
							buffer[i] = '_';
						i++;
						}
						if (i!=NbOctet){
							NbOctet = i; 
							debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Caractère final %d %d",NbOctet,i);
						}
					
						NbOctetTotal = NbOctetTotal + NbOctet;
						Nouveau_Octet_Recu (NbOctet);
					
						banniere = g_strdup_printf("%s : %s",debut_entete,buffer);
						tailleBanniere = strlen(banniere) + 1;
						break;
			default :
						return g_strdup_printf("[Error] %s  %d - %s",Protocol,(-retourLecture), strerror(-retourLecture));
		}
	}	
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "########### Bannière (%d)(Err:%d) : [%s]",tailleBanniere,retourLecture,banniere);
	if (tailleBanniere != (strlen (banniere) + 1))
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Erreur TailleBanniere (%d)!=(%d)",strlen(banniere)+1,tailleBanniere);
	if (close_control (Equip->IdSocket) < 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));
	return banniere;
}


char     *Recupere_Banniere_FTP (struct Struct_Liste_Equipement *Equip)
{
#define   BANNIERE_FTP  "FTP : "
	gchar   *Error,buffer[255];
	
	ERROR_if (Equip == NULL);
	usleep (SURCHARGE_EQUIPEMENT);	
	if ((Error = connect_service(Equip,"FTP",PORT_FTP)) != NULL)
		return Error;
	strcpy (buffer, "Bad command\n");
	if ((Error = send_service(Equip,buffer,strlen(buffer),"FTP"))!= NULL)
		return Error;
	return read_service(Equip,BANNIERE_FTP,"\r\n", "FTP",TRUE);
}


char     *Recupere_Banniere_HTTP (struct Struct_Liste_Equipement *Equip)
{
#define   BANNIERE_HTTP  "HTTP : "
	gchar   *Error,buffer[255];
	
	ERROR_if (Equip == NULL);
	usleep (SURCHARGE_EQUIPEMENT);	
	if ((Error = connect_service(Equip,"HTTP",PORT_HTTP)) != NULL)
		return Error;
	sprintf (buffer, "GET / HTTP/1.1\r\nHost: %s\r\n\r\n", Equip->Adresse_Ip_Char);
	if ((Error = send_service(Equip,buffer,strlen(buffer),"HTTP"))!= NULL)
		return Error;
	return read_service(Equip,BANNIERE_HTTP,"\r\n\r\n", "HTTP",FALSE);
}


char     *Recupere_Banniere_IMAP (struct Struct_Liste_Equipement *Equip)
{
#define   BANNIERE_IMAP  "IMAP : "
	gchar   *Error,buffer[255];
	
	ERROR_if (Equip == NULL);
	usleep (SURCHARGE_EQUIPEMENT);	
	if ((Error = connect_service(Equip,"IMAP",PORT_IMAP)) != NULL)
		return Error;
	strcpy (buffer, "Bad command\n");
	if ((Error = send_service(Equip,buffer,strlen(buffer),"IMAP"))!= NULL)
		return Error;
	return read_service(Equip,BANNIERE_IMAP,"\r\n", "IMAP",TRUE);
}

char     *Recupere_Banniere_SMTP (struct Struct_Liste_Equipement *Equip)
{
#define   BANNIERE_SMTP  "SMTP : "
	gchar   *Error,buffer[255];
	
	ERROR_if (Equip == NULL);
	usleep (SURCHARGE_EQUIPEMENT);	
	if ((Error = connect_service(Equip,"SMTP",PORT_SMTP)) != NULL)
		return Error;
	strcpy (buffer, "helo\n");
	if ((Error = send_service(Equip,buffer,strlen(buffer),"SMTP"))!= NULL)
		return Error;
	return read_service(Equip,BANNIERE_SMTP,"\r\n", "SMTP",TRUE);
}


char     *Recupere_Banniere_SSH(struct Struct_Liste_Equipement *Equip)
{
#define   BANNIERE_SSH  "SSH : "
	gchar   *Error,buffer[255];
	
	ERROR_if (Equip == NULL);
	usleep (SURCHARGE_EQUIPEMENT);	
	if ((Error = connect_service(Equip,"SSH",PORT_SSH)) != NULL)
		return Error;
	strcpy (buffer, "Help\n");
	if ((Error = send_service(Equip,buffer,strlen(buffer),"SSH"))!= NULL)
		return Error;
	return read_service(Equip,BANNIERE_SSH,"\n", "SSH",TRUE);
}




struct Struct_Option_Telnet opt_telnet[] = {
 	{TELNET_OPT_BINARY					,"8-bit data path"												,FALSE									,FALSE	,0},
	{TELNET_OPT_ECHO  						,"echo"																,FALSE	,TRUE		,TELNET_CMD_DO},
	{TELNET_OPT_RCP 						,"prepare to reconnect"									,FALSE									,FALSE	,0},
	{TELNET_OPT_SGA 							,"suppress go ahead"										,FALSE									,TRUE		,TELNET_CMD_DO},
	{TELNET_OPT_NAMS  					,"approximate message size"							,FALSE									,FALSE	,0},
	{TELNET_OPT_STATUS 					,"give status"													,TRUE 	,FALSE	,0},
	{TELNET_OPT_TM 							,"timing mark"												,TRUE	,FALSE	,0},
	{TELNET_OPT_RCTE 						,"remote controlled transmission and echo"	,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOL						,"negotiate about output line width"				,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOP						,"negotiate about output page size"					,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOCRD 					,"negotiate about CR disposition"					,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOHTS 					,"negotiate about horizontal tabstops"				,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOHTD					,"nego. about horizontal tab disposition"			,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOFFD 					,"negotiate about formfeed disposition"			,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOVTS 					,"negotiate about vertical tab stops"				,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOVTD					,"nego. about vertical tab disposition"				,FALSE									,FALSE	,0},
	{TELNET_OPT_NAOLFD 					,"negotiate about output LF disposition"			,FALSE									,FALSE	,0},
	{TELNET_OPT_XASCII 					,"extended ascii character set"						,FALSE									,FALSE	,0},
	{TELNET_OPT_LOGOUT 					,"force logout"													,FALSE									,FALSE	,0},
	{TELNET_OPT_BM 							,"byte macro"													,FALSE									,FALSE	,0},
	{TELNET_OPT_DET							,"data entry terminal"										,FALSE									,FALSE	,0},
	{TELNET_OPT_SUPDUP 					,"supdup protocol"											,FALSE									,FALSE	,0},
	{TELNET_OPT_SUPDUPOUTPUT  	,"supdup output"												,FALSE									,FALSE	,0},
	{TELNET_OPT_SNDLOC					,"send location"												,FALSE									,FALSE	,0},
	{TELNET_OPT_TTYPE 						,"terminal type"												,TRUE  ,FALSE	,0},
	{TELNET_OPT_EOR							,"end or record"												,FALSE									,FALSE	,0},
	{TELNET_OPT_TUID 						,"TACACS user identification"							,FALSE									,FALSE	,0},
	{TELNET_OPT_OUTMRK					,"output marking"											,FALSE									,FALSE	,0},
	{TELNET_OPT_TTYLOC 					,"terminal location number"							,FALSE									,FALSE	,0},
	{TELNET_OPT_3270REGIME  			,"3270 regime"												,FALSE									,FALSE	,0},
	{TELNET_OPT_X3PAD						,"X.3 PAD"														,FALSE									,FALSE	,0},
	{TELNET_OPT_NAWS  					,"window size"													,TRUE	,FALSE	,0},
	{TELNET_OPT_TSPEED 					,"terminal speed"												,TRUE	,FALSE	,0},
	{TELNET_OPT_LFLOW 					,"remote flow control"										,TRUE	,FALSE	,0},
	{TELNET_OPT_LINEMODE  				,"Linemode option"											,TRUE	,FALSE	,0},
	{TELNET_OPT_XDISPLOC 				,"X Display Location"										,TRUE  ,FALSE	,0},
	{TELNET_OPT_OLD_ENVIRON 		,"Old - Environment variables"							,TRUE	,FALSE	,0},
	{TELNET_OPT_AUTHENTICATION  	,"Authenticate"												,TRUE	,FALSE	,0},
	{TELNET_OPT_ENCRYPT 				,"Encryption option"										,TRUE	,FALSE	,0},
	{TELNET_OPT_NEW_ENVIRON 		,"New - Environment variables"						,TRUE	,FALSE	,0},
	{TELNET_OPT_TN3270E  				,"TN3270E"														,FALSE									,FALSE	,0}
};

gchar *info_option(unsigned char opt){
	if ((opt>=0) && (opt<TELNET_OPT_MAX))
		return opt_telnet[opt].info;
	else
		return "Unknown_opt";
}

void log_negociation_telnet(gchar *type,unsigned char cmd,unsigned char opt ){
	 switch(cmd) {
		 case TELNET_CMD_WILL : 
		 		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] WILL %s",type,info_option(opt));
		 		break;
		 case TELNET_CMD_WONT : 
		 		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] WONT %s",type,info_option(opt));
		 		break;
		 case TELNET_CMD_DO : 
		 		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] DO %s",type,info_option(opt));
		 		break;
	   	 case TELNET_CMD_DONT : 
		 		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] DONT %s",type,info_option(opt));
		 		break;
	   	 default : 
		 		debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "[%s] UNKNOWN cmd(%d) opt(%d)",type,cmd,opt);
		 		break;
	 }
}

void send_negociation_telnet(struct Struct_Liste_Equipement *Equipement,unsigned char cmd,unsigned char opt){
gchar negociation[3];
	
	log_negociation_telnet("Send", cmd, opt);
	negociation[0] = TELNET_IAC;
  	negociation[1] = cmd;
  	negociation[2] = opt;
	send_service(Equipement,negociation, 3,"TELNET");
}



char     *Recupere_Banniere_TELNET (struct Struct_Liste_Equipement *Equipement)
{
#define   BANNIERE_TELNET  "TELNET : "
	gchar	   *Error = NULL,*banniere = NULL, buffer[TAILLE_REQUETE_SERVICE];
	unsigned char cmd, opt;
	int Nb_Error_Consecutive,retourLecture,Tentative,NbOctet,tailleBanniere,NbOctetTotal,i,j;
	
	usleep (SURCHARGE_EQUIPEMENT);	
	ERROR_if (Equipement == NULL);
	if ((Error = connect_service(Equipement,"TELNET",PORT_TELNET)) != NULL)
		return Error;

	Nb_Error_Consecutive = 0; retourLecture = 0; NbOctet = 0; tailleBanniere = 0; NbOctetTotal = 0, Tentative = 0;

	banniere = g_strdup(BANNIERE_TELNET);
	tailleBanniere = strlen(banniere) + 1;  

	for (i=0;i<TELNET_OPT_MAX;i++)
		if (opt_telnet[i].init)
			send_negociation_telnet(Equipement,opt_telnet[i].cmd_init,i);

	while ( (Tentative!=50) && (Nb_Error_Consecutive<3) && ((retourLecture = attendre_Donnee_Lecture (Equipement->IdSocket, Time_Out_Service)) >0)) {
		NbOctet = recvfrom (Equipement->IdSocket, &buffer, ((sizeof(gchar)*TAILLE_REQUETE_SERVICE) - 1), 0, NULL, 0);
	
		if (NbOctet < 1){ 
			debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "NbOctet == %d   %s  Socket (%d) Erreur Consécutive (%d)",NbOctet, strerror (errno),Equipement->IdSocket,Nb_Error_Consecutive);
			if (NbOctet == -1){ 
				if (!(errno == EINTR || errno == EAGAIN)){
					if (close_control (Equipement->IdSocket) < 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));
					MYFREE(banniere); 
					return g_strdup ("[Error] TELNET :  NbOctet == -1");
				}
				sleep(1);
			}
			else
				sleep(1);
			Nb_Error_Consecutive++;
		}
		else {
		
			buffer[NbOctet] = 0; 
		
			NbOctetTotal = NbOctetTotal + NbOctet;
			Nouveau_Octet_Recu (NbOctet);
		
			if ((buffer[0] & 0xff) == 0xff) {
			
				i = 0;
				while ((i < (NbOctet / 3)) && ((buffer[(i * 3)] & 0xff) == 0xff)) {
					cmd = buffer[(i * 3)+1];
					opt = buffer[(i * 3) + 2] ;
					log_negociation_telnet("Read",cmd,opt);
				
					if ((opt>=0) && (opt<TELNET_OPT_MAX)) 
						if  (opt_telnet[opt].reponse){ 
							switch (cmd){
								case TELNET_CMD_WILL :
									send_negociation_telnet(Equipement,TELNET_CMD_DONT,opt);
									break;
								case TELNET_CMD_DO :
									send_negociation_telnet(Equipement,TELNET_CMD_WONT,opt);
									break;
								default :
									debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Aucune reponse necessaire");
							}
						}
					i++;
				}				
				debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "(%s)[%d]Taille retour negociation : [%d]  total:[%d]", Equipement->Adresse_Ip_Char,Tentative,(i * 3), NbOctet);
			
				if ((i * 3) < NbOctet) {
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "(%s)Des donnees après la negociation  taille(%d)", Equipement->Adresse_Ip_Char, (NbOctet - (i * 3)));
				
					for (j = (i * 3); j < NbOctet; j++)
						if ((buffer[j] != 10) && (buffer[j]  != 13) && ((buffer[j]  < 31) || (buffer[j] > 126)))
							buffer[j] = '$';
				
					buffer[NbOctet] = 0;
					tailleBanniere = tailleBanniere + (NbOctet - (i * 3));
					REALLOC(banniere,(sizeof (gchar) * (tailleBanniere)));
					strcat (banniere, (buffer + (i * 3)));
					debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "(%s) %s [%d]  TailleBanniere[%d] ", Equipement->Adresse_Ip_Char, banniere, strlen (banniere), tailleBanniere);
				}
			}
			else {
			
				for (j = 0; j < NbOctet; j++)
						if ((buffer[j] != 10) && (buffer[j]  != 13) && ((buffer[j]  < 31) || (buffer[j] > 126)))
							buffer[j] = '$';
			
				buffer[NbOctet] = 0;
				tailleBanniere = tailleBanniere + NbOctet;
				REALLOC(banniere,(sizeof (gchar) * (tailleBanniere)));
				strcat (banniere, buffer);
				debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Standard - (%s) %s [%d] TailleBanniere[%d] ", Equipement->Adresse_Ip_Char, banniere, strlen (banniere),tailleBanniere);
			}
			Nb_Error_Consecutive = 0;
		}
		Tentative++;
		retourLecture = 0;
	}
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Bannière recuperer : %s\n",banniere);

	if ((retourLecture <0)&&(tailleBanniere == (strlen(BANNIERE_TELNET) + 1))){
		MYFREE(banniere);
		switch (retourLecture){
			case SOCK_BROKEN_PIPE :
						return g_strdup_printf("[TcpWrapped] TELNET %d - %s",(-retourLecture), strerror(-retourLecture));
			default:
						return g_strdup_printf("[Error] TELNET  %d - %s",(-retourLecture), strerror(-retourLecture));
		}
	}

	if (tailleBanniere != (strlen (banniere) + 1))
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Erreur TailleBanniere (%d)!=(%d)",tailleBanniere,(strlen (banniere) + 1));
	if (close_control (Equipement->IdSocket) < 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));
	return banniere;
}
