#native_company# #native_desc#
#native_cta#

Simple telnet script class

By Marc Ennaji
on July 25, 2001

Version: 1

Type: Class

Category: Networking

License: GNU General Public License

Description: Telnet script class. Written in french, but may be translatable :-). Tested, seems to work fine.

<?

/*  

  Fichier : scriptTelnet.inc (fichier d'include dclarant la classe ScriptTelnet)
  Role de la classe : Grer un script se droulant via une socket telnet 
   
  Exemple d'utilisation, ne tenant pas compte des codes retour des methodes :

	    $script = new ScriptTelnet;
	    $script->setHote("unhote.quelquepart.fr");
	    $script->setPrompt(">");
	    $script->connecter();
	    $script->lireJusqua("ogin: "); 
	    $script->ecrire("Jojo")); 
	    $script->lireJusqua("word: "); 
	    $script->ecrire("monpasse");
	    $script->attendrePrompt();
	    $script->ecrire("ps");
	    $script->attendrePrompt();
	    $script->deconnecter();

      Auteur : Marc Ennaji

*/

define ("TELNET_ERREUR", 0);
define ("TELNET_OK", 1);
define ("TELNET_DEMANDE_CONFIRMATION", 2);
define ("LIBELLE_CONFIRMATION", "[confirm]");


Class ScriptTelnet 
{ 
    var $socket  = NULL;
    var $hote = "";
    var $port = "23";
    var $libelleErreur = "";
    var $codeErreur = "";
    var $prompt = "$ ";
    var $log = NULL;  // handle de fichier
    var $repertoireLog= ""; 
    var $nomFichierLog = "";
    var $test;

    //------------------------------------------------------------------------
      
    function connecter() 
    {
        $this->socket = fsockopen($this->hote,$this->port); 
		        
	if (! $this->socket)
	{ 
            $this->libelleErreur = "Impossible d'etablir la connexion telnet : " . strerror ($this->socket) . "n";
	    return TELNET_ERREUR;
	}
	
	socket_set_timeout($this->socket,5,0); 
	return TELNET_OK;
    }

    //------------------------------------------------------------------------
    
    function lireJusqua($chaine) 
    { 
        $NULL = chr(0); 
	$IAC = chr(255);
    	$buf = ''; 

	if (! $this->socket)
	{
	    $this->libelleErreur = "socket telnet non ouverte";
	    return TELNET_ERREUR;
	}
        
	while (1) 
	{ 
            $c = $this->getc(); 

            if ($c === false) // plus de caracteres a lire sur la socket 
	    {
	        if ($this->contientErreur($buf))
	       	    return TELNET_ERREUR;

         	$this->libelleErreur = " La chaine attendue : '" . $chaine . "', n'a pas  trouve dans les donnes reues : '" . $buf . "'" ; 
		$this->logger($this->libelleErreur);
   		return TELNET_ERREUR;
	    }

            if ($c == $NULL || $c == "21") 
            	continue; 
 
            if ($c == $IAC)  // Interpreted As Command
	    {
	    	$c = $this->getc(); 

        	if ($c != $IAC) // car le 'vrai' caractere 255 est doubl pour le differencier du IAC
	    	    if (! $this->negocierOptionTelnet($c))
		    	return TELNET_ERREUR;
		    else
		    	continue;
	    }

	    $buf .= $c; 

	    // indiquer  l'utilisateur de la classe qu'il a une demande de confirmation
	    if (substr($buf,strlen($buf)-strlen(LIBELLE_CONFIRMATION)) == LIBELLE_CONFIRMATION)
	    {
		$this->logger($this->getDernieresLignes($buf));
		return TELNET_DEMANDE_CONFIRMATION;
	    }
            
	    if ((substr($buf,strlen($buf)-strlen($chaine))) == $chaine)
	    {  
	        // on a trouve la chaine attendue
	    
	        $this->logger($this->getDernieresLignes($buf));

	        if ($this->contientErreur($buf))
	       	   return TELNET_ERREUR;
	        else
	           return TELNET_OK; 		    
	    }

        }
    }

    //------------------------------------------------------------------------
    
    function getc()
    {
    	return fgetc($this->socket);
    }

    //------------------------------------------------------------------------

    function negocierOptionTelnet($commande)
    {
         // on negocie des options minimales

        $IAC = chr(255); 
        $DONT = chr(254); 
        $DO = chr(253); 
        $WONT = chr(252); 	    
        $WILL = chr(251); 

    	if (($commande == $DO) || ($commande == $DONT)) 
    	{ 
            $opt = $this->getc();  
            //echo "wont ".ord($opt)."n"; 
            fwrite($this->socket,$IAC.$WONT.$opt); 
        } 
    	else if (($commande == $WILL) || ($commande == $WONT)) 
    	{ 
            $opt = fgetc($this->socket);  
            //echo "dont ".ord($opt)."n"; 
            fwrite($this->socket,$IAC.$DONT.$opt); 
        } else 
    	{ 
            $this->libelleErreur = "Erreur : commande inconnue ".ord($commande)."n"; 
            return false;
        } 
	return true;
    }
     
    //------------------------------------------------------------------------

    function ecrire($buffer, $valeurLoggee = "", $ajouterfinLigne = true) 
    {			     
	if (! $this->socket)
	{
	    $this->libelleErreur = "socket non ouverte";
	    return TELNET_ERREUR;
	}

	if ($ajouterfinLigne)
	    $buffer .= "n";

        if (fwrite($this->socket,$buffer) < 0)
	{
	    $this->libelleErreur = "erreur d'ecriture sur la socket telnet";
	    return TELNET_ERREUR;
	}

	if ($valeurLoggee != "")  // cacher les valeurs confidentielles dans la log (mots de passe...)
	    $buffer = $valeurLoggee . "n";

	if (! $ajouterfinLigne)  // dans la log (mais pas sur la socket), rajouter tout de meme le caractere de fin de ligne
	    $buffer .= "n";

       	$this->logger("> " .$buffer); 

	return TELNET_OK;
    } 

    //------------------------------------------------------------------------

    function deconnecter() 
    {                    
        if ($this->socket) 
	{
            if (! fclose($this->socket))
	    {
	    	$this->libelleErreur = "erreur a la fermeture de la socket telnet";
		return TELNET_ERREUR;
	    }
	    $this->socket = NULL; 
	}
	$this->setLog(false,"");

        return TELNET_OK;
    }
    //------------------------------------------------------------------------

    function contientErreur($buf) 
    {   
    	$messagesErreurs[] = "nvalid";		// Invalid input, ...
	$messagesErreurs[] = "o specified";     // No specified atm, ...
	$messagesErreurs[] = "nknown";	        // Unknown profile, ...
	$messagesErreurs[] = "o such file or directory"; // sauvegarde dans un repertoire inexistant
	$messagesErreurs[] = "llegal";		// illegal file name, ...

	foreach ($messagesErreurs as $erreur)
	{
	    if (strpos ($buf, $erreur) === false)
	    	continue;

	    // une erreur est dtecte
   	    $this->libelleErreur =  "Un message d'erreur a t dtect dans la rponse de l'hte distant : " . 
	    			   "<BR><BR>" . $this->getDernieresLignes($buf,"<BR>") . "<BR>";

	    return true;
	}
	return false;
    }

    //------------------------------------------------------------------------

    function attendrePrompt()
    {
        return $this->lireJusqua($this->prompt);
    }

    //------------------------------------------------------------------------

    function setPrompt($s) { $this->prompt = $s; return TELNET_OK; }
    //------------------------------------------------------------------------

    function setHote($s) { $this->hote = $s;}

    //------------------------------------------------------------------------

    function setPort($s) { $this->port = $s;}

    //------------------------------------------------------------------------

    function getDerniereErreur() { return $this->libelleErreur; }

    //------------------------------------------------------------------------

    function setLog($activerLog, $traitement) 
    { 
        if ($this->log && $activerLog)  
	    return TELNET_OK;
	  
        if ($activerLog)   
	{
	    $this->repertoireLog =  "/log/" . date("m");

	    if (! file_exists($this->repertoireLog)) // repertoire mensuel inexistant ?
	    {
	    	if (mkdir($this->repertoireLog, 0700) === false)
            	{
             	    $this->libelleErreur = "Impossible de crer le repertoire de log " .  $this->repertoireLog;
             	    return TELNET_ERREUR;
            	}
	    }
	    global $HTTP_SERVER_VARS;
	    $this->nomFichierLog = 	date("d") . "_" . 
	    				date("H:i:s") . "_" . 
					$traitement . "_" . 
					$HTTP_SERVER_VARS["PHP_AUTH_USER"]
	    				. ".log"; 
            $this->log = fopen($this->repertoireLog . "/" . $this->nomFichierLog,"a");
                
            if (empty($this->log))
            {
             	$this->libelleErreur = "Impossible de crer le fichier de log " . $this->nomFichierLog;
             	return TELNET_ERREUR;
            }
	    $this->logger("----------------------------------------------rn");
	    $this->logger("Dbut de la log de l'utilisateur " . $HTTP_SERVER_VARS["PHP_AUTH_USER"] . 
	    		", adresse IP " . $HTTP_SERVER_VARS["REMOTE_ADDR"] . "rn");
	    $this->logger("Connexion telnet sur " . $this->hote . ", port " . $this->port . "rn");
      	    $this->logger("Date : " . date("d-m-Y").  "   " . date("H:i:s") . "rn");
     	    $this->logger("Type de traitement effectu : " . $traitement . "rn");
	    $this->logger("----------------------------------------------rn");
	    return TELNET_OK;
	}
	else
	{
	    if ($this->log) 
	    {
	    	$this->logger("----------------------------------------------rn");
	    	$this->logger("Fin de la logrn");
	    	fflush($this->log);
	        if (! fclose($this->log))
	        {
	       	    $this->libelleErreur = "erreur a la fermeture du fichier de log";
		    return TELNET_ERREUR;
		}
		$this->log = NULL; 
	    }
	    return TELNET_OK;
	}
    }

    //------------------------------------------------------------------------

    function logger($s)
    {
    	if ($this->log)
	    fwrite($this->log, $s);  
    }
    //------------------------------------------------------------------------

    function getDernieresLignes($s, $separateur="n")
    {
        // une reponse telnet contient (en principe) en premiere ligne l'echo de la commande utilisateur.
	// cette methode renvoie tout sauf la premiere ligne, afin de ne pas polluer les logs telnet

        $lignes = split("n",$s);
	$resultat = "";
	$premiereLigne = true;
        
        while(list($key, $data) = each($lignes))
        {
	    if ($premiereLigne)
	    	$premiereLigne = false;
	    else
	        if ($data != "")
	    	    $resultat .= $data . $separateur;
        }
	$resultat == substr($resultat,strlen($resultat)-1); // enlever le dernier caractere de fin de ligne

	return $resultat;
    }
    
    //------------------------------------------------------------------------


}   //    Fin de la classe                    
?>