<?php
/**
 * Cliente que usa las funciones básicas del protocolo/Client that uses the basic functions of the protocol
 *
 * @author     Sinfocol
 * @copyright  2009 www.sinfocol.org
 * @version    Release: 2.1.17
 * @link       http://www.sinfocol.org/2009/06/thewalrusbot-un-cliente-irc-sencillo-en-php/
 * @since      Class available since Release 2.1.17
 */
set_time_limit(0);
class 
Cliente{
    public 
$verbose false;
    public 
$veryverbose false;
    public 
$log false;
    public 
$sep;
    public 
$servidor;
    public 
$puerto;
    public 
$canal;
    public 
$nick;
    public 
$clave;
    public 
$nombre;
    public 
$php;

    private 
$version '2.1.17';
    private 
$cli;
    private 
$archivo;
    private 
$umsg '';
    private 
$logged false;
    private 
$encanal false;
    private 
$socket;

    public function 
__construct(){
        if(
php_sapi_name() == 'cli'){
            
$this->cli true;
            
$this->sep "\r\n";
        }else{
            
$this->cli false;
            
$this->sep "<br>\r\n";
            
ob_implicit_flush();
        }
        include(
'IrcParser.php');
    }

    
/**
     * Realiza la conexión cliente-servidor/Performs the client-server connection
     * @return void
     */
    
public function conectar(){
        if(
strval($this->puerto) <=|| strval($this->puerto 65535))
            
$this->puerto 6667;
        
        
$this->socket = @fsockopen($this->servidor$this->puerto$errno$errstr300);

        if(!
$this->socket){
            
$this->_msg("No se pudo establecer la comunicación con {$this->servidor}"false);
            die;
        }
        
        if(
$this->sep == false){
            
$this->sep $this->cli "\r\n""<br>\r\n";
        }
        if(
$this->log){
            
ob_start();
            
$this->archivo fopen('IRC_' date('d-m-Y_h-s-i'time()) . '.log''w');
        }

        
$nickname '/^[\-\d\x41-\x7d]+$/';
        if(
preg_match($nickname$this->nick) == false)
            
$this->nick $this->_caracteresAleatorios(10'abcdefghijklmnopqrstuvwxyz');

        if(empty(
$this->nombre))
            
$this->nombre "TheWalrusBot {$this->version}";

        
$this->_msg("Iniciando el cliente"false);

        
$irc  '';
        
$parser = new IrcParser();
        while( !
feof($this->socket) ){
            
//Se obtienen los datos del socket y se procesan con el IrcParser
            
$irc $parser->parsefgets($this->socket) );
            
$this->_msg($irc);

            
/*****************************************************************************************************\
             * Contiene los mensajes básicos y las respuestas a todos los comandos que proporcionamos al servidor |
             * Este bloque de código se puede borrar, aunque contiene el funcionamiento básico del cliente tal    |
             * como responder a un PING, iniciar la negociación de registro con el servidor o ingresar al canal   |
             \****************************************************************************************************/
            
switch($irc['command']){
                case 
'NOTICE':
                    if(!
$logged && $irc['middle'][0] == 'AUTH'){
                        
$logged true;
                        
//Inicializa la negociación siguiendo el RFC/Initialize the handshaking following the RFC
                        //PASS password
                        
if(isset($this->clave))
                            
$this->_out"PASS {$this->clave});
                        
// NICK nick
                        
$this->_out"NICK {$this->nick});
                        
//USER nombre_de_usuario modo sin_uso :nombre_real
                        
$this->_out"USER {$this->nick} 8 * :{$this->nombre});
                    }
                    break;

                case 
'PING':
                    
$this->_out'PONG :' $irc['trailing'] );
                    break;

                case 
'PRIVMSG':
                    if(
$irc['trailing'] == "\x01VERSION\x01")
                        
$this->_out'NOTICE ' $irc['nickname'] . " :\x01VERSION {$this->nick}{$this->version}\x01" );

                    break;

                
/*
                 * Respuestas para los comandos
                 *
                 * Los comentarios se basan en tres líneas
                 * 1. Constante para la respuesta
                 * 2. Formato del mensaje de respuesta
                 * 3. Breve explicación de la respuesta
                 */
                
case '001':
                    
//RPL_WELCOME
                    //"Welcome to the Internet Relay Network <nick>!<user>@<host>"
                    //Bienvenido al IRC
                    
break;

                case 
'002':
                    
//RPL_YOURHOST
                    //"Your host is <servername>, running version <ver>"
                    //Tu host es x, corriendo la versión x
                    
break;

                case 
'003':
                    
//RPL_CREATED
                    //"This server was created <date>"
                    //Este servidor fue creado <fecha>
                    
break;

                case 
'004':
                    
//RPL_MYINFO
                    //"<servername> <version> <available user modes> <available channel modes>"
                    //<nombre del servidor> <version> <modos de usuario disponibles> <modos de canal disponibles>
                    
break;

                case 
'005':
                    
//RPL_BOUNCE
                    //"Try server <server name>, port <port number>"
                    //Enviado por el servidor al usuario sugiriendole un servidor alternativo
                    /*La idea para esta respuesta sería hacer algo así:
                     *fclose($this->socket);
                     *$this->socket = fsockopen('servidor', puerto);
                     */
                    
break;

                case 
'302':
                    
//RPL_USERHOST
                    //":*1<reply> *( " " <reply> )"
                    //Formato de respuesta usado por el comando USERHOST
                    
break;

                case 
'303':
                    
//RPL_ISON
                    //":*1<nick> *( " " <nick> )"
                    //Formato de respuesta usado por el comando ISON
                    
break;

                case 
'301':
                    
//RPL_AWAY
                    //"<nick> :<away message>"
                    //El nick está ausente
                    
break;

                case 
'305':
                    
//RPL_UNAWAY
                    //":You are no longer marked as being away"
                    //El nick volvió
                    
break;

                case 
'306':
                    
//RPL_NOWAWAY
                    //":You have been marked as being away"
                    //El nick se acabó de ir
                    
break;

                case 
'311':
                    
//RPL_WHOISUSER
                    //"<nick> <user> <host> * :<real name>"
                    //Retorna el nick, usuario, host, y nombre real de un nick
                    
break;

                case 
'312':
                    
//RPL_WHOISSERVER = Retorna contenido acerca del servidor
                    
break;

                case 
'313':
                    
//RPL_WHOISOPERATOR
                    //"<nick> <server> :<server info>
                    //Nos dice si el nick es un operador
                    
break;

                case 
'317':
                    
//RPL_WHOISIDLE
                    //"<nick> <integer> :seconds idle"
                    //Segundos que el nick ha estado inactivo
                    
break;

                case 
'318':
                    
//RPL_ENDOFWHOIS
                    //"<nick> :End of WHOIS list"
                    //Finaliza la lista para el comando WHOIS
                    
break;

                case 
'319':
                    
//RPL_WHOISCHANNELS
                    //"<nick> :*( ( "@" / "+" ) <channel> " " )"
                    //Información acerca del canal
                    
break;

                case 
'314':
                    
//RPL_WHOWASUSER
                    //"<nick> <user> <host> * :<real name>"
                    //Retorna el nick, usuario, host, y nombre real de un nick que estuvo en al IRC
                    
break;

                case 
'369':
                    
//RPL_ENDOFWHOWAS
                    //"<nick> :End of WHOWAS"
                    //Finaliza información para el comando WHOWAS
                    
break;

               case 
'321':
                   
//RPL_LISTSTART
                   //
                   //Obsoleto. No usado
                   
break;

               case 
'322':
                   
//RPL_LIST
                   //"<channel> <# visible> :<topic>"
                   //Retorna el canal, el tema y la visibilidad de un canal
                   
break;

               case 
'323':
                   
//RPL_LISTEND
                   //":End of LIST"
                   //Finaliza el comando LIST
                   
break;

               case 
'325':
                   
//RPL_UNIQOPIS
                   //"<channel> <nickname>"
                   //
                   
break;

               case 
'324':
                   
//RPL_CHANNELMODEIS
                   //"<channel> <mode> <mode params>"
                   //Retorna el modo del canal
                   
break;

               case 
'331':
                   
//RPL_NOTOPIC
                   //"<channel> :No topic is set"
                   //No se ha configurado un tema para el canal
                   
break;

               case 
'332':
                   
//RPL_TOPIC
                   //"<channel> :<topic>"
                   //Retorna el tema del canal cuando ingresamos a este
                   
break;
                   
               case 
'341':
                   
//RPL_INVITING
                   //"<channel> <nick>"
                   //Cuando el comando INVITE ha sido correctamente ejecutado
                   
break;

               case 
'342':
                   
//RPL_SUMMONING
                   //"<user> :Summoning user to IRC"
                   //Devuelto por el servidor respondiendo el comando SUMMON que indica que se está convocando al usuario
                   
break;

               case 
'346':
                   
//RPL_INVITELIST
                   //"<channel> <invitemask>"
                   //Cuando listando las "máscaras de invitación" para un canal dado, el servidor requerido envia la lista usando RPL_INVITELIST y RPL_ENDOFINVITELIST. Separados RPL_INVITELIST son enviados para cada máscara activa
                   
break;

               case 
'347':
                   
//RPL_ENDOFINVITELIST
                   //"<channel> :End of channel invite list"
                   //Finaliza la lista de los invitados dados para el canal
                   
break;

               case 
'348':
                   
//RPL_EXCEPTLIST
                   //"<channel> <exceptionmask>"
                   //Cuando listando las "máscaras de excepción" para un canal dado, el servidor requerido envia la lista usando RPL_EXCEPTLIST y RPL_ENDOFEXCEPTLIST. Separados RPL_EXCEPTLIST son enviados para cada máscara activa
                   
break;

               case 
'349':
                   
//RPL_ENDOFEXCEPTLIST
                   //"<channel> :End of channel exception list"
                   //Finaliza la lista de las excepciones dadas para el canal
                   
break;

               case 
'351':
                   
//RPL_VERSION
                   //"<version>.<debuglevel> <server> :<comments>"
                   //Retorna los detalles de la versión del servidor
                   
break;

               case 
'352':
                   
//RPL_WHOREPLY
                   //"<channel> <user> <host> <server> <nick> ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] :<hopcount> <real name>"
                   //Respuesta al comando WHO
                   
break;

               case 
'315':
                   
//RPL_ENDOFWHO
                   //"<name> :End of WHO list"
                   //Finaliza la respuesta para el comando WHO
                   
break;

               case 
'353':
                   
//RPL_NAMREPLY
                   //"( "=" / "*" / "@" ) <channel> :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
                   //Respuesta al comando NAMES. @ es usado para canales secretos, * para privados y = para los públicos.
                   
break;

               case 
'366':
                   
//RPL_ENDOFNAMES
                   //"<channel> :End of NAMES list"
                   //Finaliza la respuesta para el comando NAMES
                   
break;

               case 
'364':
                   
//RPL_LINKS
                   //"<mask> <server> :<hopcount> <server info>"
                   //Respuesta al comando LINKS
                   
break;

               case 
'365':
                   
//RPL_ENDOFLINKS
                   //"<mask> :End of LINKS list"
                   //Finaliza la lista para el comando LINKS
                   
break;

               case 
'367':
                   
//RPL_BANLIST
                   //"<channel> <banmask>"
                   //Retorna una lista con las conexiones denegadas
                   
break;

               case 
'368':
                   
//RPL_ENDOFBANLIST
                   //"<channel> :End of channel ban list"
                   //Finaliza la lista de las conexiones denegadas
                   
break;

               case 
'371':
                   
//RPL_INFO
                   //":<string>"
                   //Respuesta al comando INFO que retorna información acerca del servidor
                   
break;

               case 
'374':
                   
//RPL_ENDOFINFO
                   //":End of INFO list"
                   //Finaliza la lista de la información del servidor
                   
break;

               case 
'375':
                   
//RPL_MOTDSTART
                   //":- <server> Message of the day - "
                   //Inicia el mensaje del día del servidor
                   
break;

               case 
'372':
                   
//RPL_MOTD
                   //":- <text>"
                   //Contiene los mensajes del día
                   
break;

               case 
'376':
                   
//RPL_ENDOFMOTD
                   //":End of MOTD command"
                   //Termina de enviar los mensajes del día
                   
if(!$this->encanal && isset($this->canal)){
                       
$this->_out"JOIN {$this->canal});
                       
$this->encanal true;
                   }
                   break;

               case 
'381':
                   
//RPL_YOUREOPER
                   //":You are now an IRC operator"
                   //Devuelto al cliente cuando ganó exitosamente el estado de operador de IRC
                   
break;

               case 
'382':
                   
//RPL_REHASHING
                   //"<config file> :Rehashing"
                   //Si la opción REHASH es usada y un operador envia el comando REHASH, la respuesta es devuelta al operador por RPL_HASHING
                   
break;

               case 
'383':
                   
//RPL_YOURESERVICE
                   //"You are service <servicename>"
                   //Enviado por el servidor luego de que se registró exitosamente un servicio
                   
break;

               case 
'391':
                   
//RPL_TIME
                   //"<server> :<string showing server's local time>"
                   //El servidor debería enviar esta respuesta luego de que el comando TIME es requerido por el cliente.
                   
break;

               case 
'392':
                   
//RPL_USERSSTART
                   //":UserID   Terminal  Host"
                   //Comienza la lista para el comando USERS
                   
break;

               case 
'393':
                   
//RPL_USERS
                   //":<username> <ttyline> <hostname>
                   //Retorna una lista de los usuarios
                   
break;

               case 
'394':
                   
//RPL_ENDOFUSERS
                   //":End of users"
                   //Finaliza la lista para el comando USERS
                   
break;

               case 
'395':
                   
//RPL_NOUSERS
                   //":Nobody logged in"
                   //No encontró ningún usuario que inicio sesión en el IRC
                   
break;

               case 
'200':
                   
//RPL_TRACELINK
                   //"Link <version & debug level> <destination> <next server> V<protocol version> <link uptime in seconds> <backstream sendq> <upstream sendq>"
                   //Es retornado cuando cualquier servidor proceso el comando TRACE y lo tiene que pasar a otro servidor
                   
break;

               case 
'201':
                   
//RPL_TRACECONNECTING
                   //"Try. <class> <server>"
                   //La conexión aún está intentado establecerse
                   
break;

               case 
'202':
                   
//RPL_TRACEHANDSHAKE
                   //"H.S. <class> <server>"
                   //Está a punto de completarse la negociación con el servidor
                   
break;

               case 
'203':
                   
//RPL_TRACEUNKNOWN
                   //"???? <class> [<client IP address in dot form>]"
                   //La conexión no está establecida o es desconocida
                   
break;

               case 
'204':
                   
//RPL_TRACEOPERATOR
                   //"Oper <class> <nick>"
                   //
                   
break;

               case 
'205':
                   
//RPL_TRACEUSER
                   //"User <class> <nick>"
                   //
                   
break;

               case 
'206':
                   
//RPL_TRACESERVER
                   //"Serv <class> <int>S <int>C <server> <nick!user|*!*>@<host|server> V<protocol version>"
                   //
                   
break;

               case 
'207':
                   
//RPL_TRACESERVICE
                   //"Service <class> <name> <type> <active type>"
                   //
                   
break;

               case 
'208':
                   
//RPL_TRACENEWTYPE
                   //"<newtype> 0 <client name>"
                   //
                   
break;

               case 
'209':
                   
//RPL_TRACECLASS
                   //"Class <class> <count>"
                   //
                   
break;

               case 
'210':
                   
//RPL_TRACERECONNECT
                   //Unused.
                   //Sin uso
                   
break;

               case 
'261':
                   
//RPL_TRACELOG
                   //"File <logfile> <debug level>"
                   //
                   
break;

               case 
'262':
                   
//RPL_TRACEEND
                   //"<server name> <version & debug level> :End of TRACE"
                   //Finaliza todos los mensajes para el comando TRACE
                   
break;

               case 
'211':
                   
//RPL_STATSLINKINFO
                   //"<linkname> <sendq> <sent messages> <sent Kbytes> <received messages> <received Kbytes> <time open>"
                   //Reporta estadísticas en una conexión. linkname identifica la conexión particular, sendq es la cantidad de datos que está en la cola y espera para ser enviada, sent messages el número de mensajes enviados, y sentkbytes la cantidad de datos enviados, en kilobytes. received messages y received bytes son los equivalentes para sent messages y sent kbytes para los datos recibidos respectivamente. time open indica cuanto tiempo en segundos ha estado la conexión abierta.
                   
break;

               case 
'212':
                   
//RPL_STATSCOMMANDS
                   //"<command> <count> <byte count> <remote count>"
                   //Reporta estadísitcas acerca del uso de un comando
                   
break;

               case 
'219':
                   
//RPL_ENDOFSTATS
                   //"<stats letter> :End of STATS report"
                   //Finaliza el reporte para el comando STATS
                   
break;

               case 
'242':
                   
//RPL_STATSUPTIME
                   //":Server Up %d days %d:%02d:%02d"
                   //Reporta el tiempo de vida del servidor
                   
break;

               case 
'243':
                   
//RPL_STATSOLINE
                   //"O <hostmask> * <name>"
                   //Reportan los hosts permitidos de donde los usuarios pueden volverse operadores de IRC
                   
break;

               case 
'221':
                   
//RPL_UMODEIS
                   //"<user mode string>"
                   //Para responder una consulta acerca del modo del propio cliente
                   
break;

               case 
'234':
                   
//RPL_SERVLIST
                   //"<name> <server> <mask> <type> <hopcount> <info>"
                   //Es retornado cuando se listan los servicios de un servidor con SERVLIST
                   
break;

               case 
'235':
                   
//RPL_SERVLISTEND
                   //"<mask> <type> :End of service listing"
                   //Finaliza la lista para el comando SERVLIST
                   
break;

               case 
'251':
                   
//RPL_LUSERCLIENT
                   //":There are <integer> users and <integer> services on <integer> servers"
                   //Información general acerca de la red entera, cuando es usado el comando LUSERS sin parámetros
                   
break;

               case 
'252':
                   
//RPL_LUSEROP
                   //"<integer> :operator(s) online"
                   //Retorna la cantidad de operadores de IRC que se encuentran en línea
                   
break;

               case 
'253':
                   
//RPL_LUSERUNKNOWN
                   //"<integer> :unknown connection(s)"
                   //Información acerca de las conexiones desconocidas
                   
break;

               case 
'254':
                   
//RPL_LUSERCHANNELS
                   //"<integer> :channels formed"
                   //Información acerca de los canales formados
                   
break;

               case 
'255':
                   
//RPL_LUSERME
                   //":I have <integer> clients and <integer> servers"
                   //Información acerca del propio usuario
                   
break;

               case 
'256':
                   
//RPL_AMDINME
                   //"<server> :Administrative info"
                   //Información acerca del administrador del servidor contenido en el parámetro
                   
break;

               case 
'257':
                   
//RPL_AMDINLOC1
                   //":<admin info>"
                   //Provee información de la ciudad, estado y país donde se encuentra el servidor
                   
break;

               case 
'258':
                   
//RPL_AMDINLOC2
                   //":<admin info>"
                   //Provee información detallada de la institución
                   
break;

               case 
'259':
                   
//RPL_ADMINEMAIL
                   //":<admin info>"
                   //Provee información acerca del contacto con el servidor, una dirección de correo es REQUERIDA
                   
break;

               case 
'263':
                   
//RPL_TRYAGAIN
                   //"<command> :Please wait a while and try again."
                   //Cuando el servidor borra un comando sin procesarlo
                   
sleep(5);
                   
$this->_out$this->umsg );
                   break;

                
/**
                 * Respuestas de error
                 */
                
case '401':
                    
//ERR_NOSUCHNICK
                    //"<nickname> :No such nick/channel"
                    //Usado para indicar que el nickname enviado en el parámetro está actualmente sin uso
                    
break;

                case 
'402':
                    
//ERR_NOSUCHSERVER
                    //"<server name> :No such server"
                    //El nombre del servidor no existe actualmente
                    
break;

                case 
'403':
                    
//ERR_NOSUCHCHANNEL
                    //"<channel name> :No such channel"
                    //No existe el canal proporcionado
                    
break;

                case 
'404':
                    
//ERR_CANNOTSENDTOCHAN
                    //"<channel name> :Cannot send to channel"
                    //Mensaje enviado a un usuario que: no está en un canal con modo +n, o no es un operador de canal en un canal con modo +m y que trata de enviar un mensaje a ese canal
                    
break;

                case 
'405':
                    
//ERR_TOOMANYCHANNELS
                    //"<channel name> :You have joined too many channels"
                    //Se ha entrado a demasiados canales
                    
break;

                case 
'406':
                    
//ERR_WASNOSUCHNICK
                    //"<nickname> :There was no such nickname"
                    //No hay información cuando se usa WHOWAS
                    
break;

                case 
'407':
                    
//ERR_TOOMANYTARGETS
                    //"<target> :<error code> recipients. <abort message>"
                    //Retornado al cliente que está tratando de enviar un PRIVMSG/NOTICE usando el formato de destino "user@host" pero hay varias ocurrencias, cuando trata de enviar un PRIVMSG/NOTICE a muchos recipientes, o cuando está intentando realizar un JOIN a un canal seguro usando un nombre corto cuando hay mas de uno de esos canales
                    
break;

                case 
'408':
                    
//ERR_NOSUCHSERVICE
                    //"<service name> :No such service"
                    //Ocurre al enviar un SQUERY a un servicio que no existe
                    
break;

                case 
'409':
                    
//ERR_NOORIGIN
                    //":No origin specified"
                    //Comando PING o PONG perdieron el parámetro de origen
                    
break;

                case 
'411':
                    
//ERR_NORECIPIENT
                    //":No recipient given (<command>)"
                    //No hubo un recipiente dado por el comando
                    
break;

                case 
'412':
                    
//ERR_NOTEXTTOSEND
                    //":No text to send"
                    //No hay texto para enviar
                    
break;

                case 
'413':
                    
//ERR_NOTOPLEVEL
                    //"<mask> :No toplevel domain specified"
                    //No hay un dominio especificado
                    
break;

                case 
'414':
                    
//ERR_WILDTOPLEVEL
                    //"<mask> :Wildcard in toplevel domain"
                    //Comodín en el dominio
                    
break;

                case 
'421':
                    
//ERR_UNKNOWNCOMMAND
                    //"<command> :Unknown command"
                    //Retornado a un cliente indicando que el comando enviado es desconocido por el servidor
                    
break;

                case 
'422':
                    
//ERR_NOMOTD
                    //":MOTD File is missing"
                    //El servidor no puede abrir el archivo MOTD
                    
if(!$this->encanal && isset($this->canal)){
                        
$this->_out"JOIN {$this->canal});
                        
$this->encanal true;
                    }
                    break;

                case 
'423':
                    
//ERR_NOAMDININFO
                    //"<server> :No administrative info available"
                    //Retornado por el servidor en respuesta al comando ADMIN cuando hay un error encontrando la información
                    
break;

                case 
'424':
                    
//ERR_FILEERROR
                    //":File error doing <file op> on <file>"
                    //Error genérico usado para reportar una operación de archivo fallido durante el proceso del mensaje
                    
break;

                case 
'431':
                    
//ERR_NONICKNAMEGIVEN
                    //":No nickname given"
                    //Retornado cuando el parámetro del nickname no fue encontrado
                    
$this->nick $this->_caracteresAleatorios(10);
                    
$this->_out"NICK {$this->nick});
                    break;

                case 
'432':
                    
//ERR_ERRONEUSNICKNAME
                    //"<nick> :Erroneous nickname"
                    //Retornado luego de recibir el comando NICK el cual contenía carácteres inapropiados
                    
$this->nick $this->_caracteresAleatorios(10);
                    
$this->_out"NICK {$this->nick});
                    break;

                case 
'433':
                    
//ERR_NICKNAMEINUSE
                    //"<nick> :Nickname is already in use"
                    //Cuando se trata de iniciar con un nickname ya usado
                
case '436':
                    
//ERR_NICKCOLLISION
                    //"<nick> :Nickname collision KILL from <user>@<host>"
                    //Cuando se trata de iniciar con un nickname que existe en otro servidor
                    
$this->nick "_{$this->nick}{$this->_caracteresAleatorios(3)}_";
                    
$this->_out"NICK {$this->nick});
                    break;

                case 
'437':
                    
//ERR_UNAVAILRESOURCE
                    //"<nick/channel> :Nick/channel is temporarily unavailable"
                    //Cuando el nick o el canal están temporalmente no disponibles
                    
sleep(5);
                    
$tmp $this->umsg;
                    
$this->umsg '';
                    
$this->out$tmp );
                    break;

                case 
'441':
                    
//ERR_USERNOTINCHANNEL
                    //"<nick> <channel> :They aren't on that channel"
                    //Se envia un mensaje a un usuario que no está en el canal especificado
                    
break;

                case 
'442':
                    
//ERR_NOTONCHANNEL
                    //"<channel> :You're not on that channel"
                    //Enviamos un mensaje en un canal en el que no nos encontramos
                    
if( isset($this->canal) ){
                        
$this->_out"JOIN {$this->canal});
                        
$this->encanal true;
                    }
                    break;

                case 
'443':
                    
//ERR_USERONCHANNEL
                    //"<user> <channel> :is already on channel"
                    //Tratamos de invitar a un usuario que ya está en el canal
                    
break;

                case 
'444':
                    
//ERR_NOLOGIN
                    //"<user> :User not logged in"
                    //Retornado luego de que el comando SUMMON fue incapáz de realizar su acción cuando el usuario no ha iniciado sesión
                    
break;

                case 
'445':
                    
//ERR_SUMMONDISABLED
                    //":SUMMON has been disabled"
                    //El comando SUMMON no está implemetando por el servidor
                    
break;

                case 
'446':
                    
//ERR_USERDISABLED
                    //":USERS has been disabled"
                    //Es una respuesta al comando USERS, debería ser retornado por el servidor que no lo tenga implemetando
                    
break;

                case 
'451':
                    
//ERR_NOTREGISTERED
                    //":You have not registered"
                    //El servidor indica que el cliente debería estar registrado antes que el servidor esté permitido a procesarlo en detalle
                    
break;

                case 
'461':
                    
//ERR_NEED_MOREPARAMS
                    //"<command> :Not enough parameters"
                    //El comando necesita más parámetros
                    
break;

                case 
'462':
                    
//ERR_ALREADYREGISTERED
                    //":Unauthorized command (already registered)"
                    //Comando no autorizado: Se está tratando de cambiar parte de los detalles del registrado tales como clave o detalles del usuario
                    
break;

                case 
'463':
                    
//ERR_NOPERMFORHOST
                    //":Your host isn't among the privileged"
                    //Devuelto al cliente cuando se trata de registrar con un servidor que no ha sido configurado para permitir la conexión del host del cual proviene el cliente
                    
break;

                case 
'464':
                    
//ERR_PASSWDMISMATCH
                    //":Password incorrect"
                    //Clave incorrecta o clave requerida
                    
$this->logged false;
                    break;

                case 
'465':
                    
//ERR_YOUAREBANNEDCREP
                    //":You are banned from this server"
                    //Se ha denegado la conexión hacía nuestro cliente
                    
break;

                case 
'466':
                    
//ERR_YOUWILLBEBANNED
                    //
                    //Nos informan que pronto se nos denegará la conexión
                    
break;

                case 
'467':
                    
//ERR_KEYSET
                    //"<channel> :Channel key already set"
                    //La llave del canal ya está configurada
                    
break;

                case 
'471':
                    
//ERR_CHANNELISFULL
                    //"<channel> :Cannot join channel (+l)"
                    //El canal está lleno y no podemos entrar
                    
$this->encanal false;
                    break;

                case 
'472':
                    
//ERR_UNKNOWNMODE
                    //"<char> :is unknown mode char to me for <channel>"
                    //Es desconocido el modo enviado
                    
break;

                case 
'473':
                    
//ERR_INVITEONLYCHAN
                    //"<channel> :Cannot join channel (+i)"
                    //No se puede ingresar al canal, ya que solo permiten invitados
                    
break;

                case 
'474':
                    
//ERR_BANNEFROMCHAN
                    //"<channel> :Cannot join channel (+b)"
                    //No se puede ingresar al canal porque hemos sido baneados
                    
break;

                case 
'475':
                    
//ERR_BADCHANNELKEY
                    //"<channel> :Cannot join channel (+k)"
                    //La clave del canal es errónea
                    
break;

                case 
'476':
                    
//ERR_BADCHANMASK
                    //"<channel> :Bad Channel Mask"
                    //Mala máscara para el canal
                    
break;

                case 
'477':
                    
//ERR_NOCHANMODSE
                    //"<channel> :Channel doesn't support modes"
                    //El canal no soporta el uso de modos
                    
break;

                case 
'478':
                    
//ERR_BANLISTFULL
                    //"<channel> <char> :Channel list is full"
                    //La lista del canal está llena
                    
break;

                case 
'481':
                    
//ERR_NOPRIVILEGES
                    //":Permission Denied- You're not an IRC operator"
                    //Cualquier comando requiere privilegios de operador IRC para poder operar significa que no se ejecutó el comando
                    
break;

                case 
'482':
                    
//ERR_CHANOPRIVSNEEDED
                    //"<channel> :You're not channel operator"
                    //Similar al anterior error, ahora se requiere que el cliente sea operador del canal
                    
break;

                case 
'483':
                    
//ERR_CANTKILLSERVER
                    //":You can't kill a server!"
                    //Cualquier intento de usar el comando KILL y el servidor se negó a ejecutarlo
                    
break;

                case 
'484':
                    
//ERR_RESTRICTED
                    //":Your connection is restricted!"
                    //Nuestra conexión ha sido restringida
                    
fclose($this->socket);
                    break;

                case 
'485':
                    
//ERR_UNIQOPPRIVSNEEDED
                    //":You're not the original channel operator"
                    //El cliente no es el operador original del canal
                    
break;

                case 
'491':
                    
//ERR_NOOPERHOST
                    //":No O-lines for your host"
                    //Cuando el cliente envia el comando OPER y el servidor no ha sido configurado para permitir la conexión del cliente como un operador
                    
break;

                case 
'501':
                    
//ERR_UMODEUNKNOWNFLAG
                    //":Unknown MODE flag"
                    //La bandera enviada con el comando MODE no fue reconocida
                    
break;

                case 
'502':
                    
//ERR_USERSDONTMATCH
                    //":Cannot change mode for other users"
                    //No se puede cambiar el modo de otros usuarios
                    
break;

            } 
//Fin switch($irc['command'])

            //Si $this->php tiene contenido, lo ejecutamos con la función eval() y capturamos los errores para que no interfiera con la conexión
            
if( isset($this->php) ){
                try{
                    eval(
$this->php);
                }catch(
Exception $e){
                }
            }

        } 
//Fin while(!feof($this->socket))

    
//Fin función conectar()

    /**
     * Muestra el mensaje asociado y lo almacena en un archivo si $this->log es indicado antes de iniciar la conexión
     * @param string $mensaje Mensaje a escribir en la salida estándar o en el cliente web
     * @param bool $irc Determina si el mensaje es un mensaje procesado por el IrcParser, o si es un mensaje común. True => Asociado a IrcParser, False => Asociado a mensaje común
     * @return void
     */
    
private function _msg($mensaje$irc true){
        
$msg '';
        if(
$this->verbose){
            if(
$irc){ //Si es un mensaje IRC imprimimos su mensaje crudo
                
$msg trim($mensaje['raw']);
            }else{ 
//Sino, simplemente imprimimos el mensaje
                 
$msg $mensaje;
            }
            
//Agregamos el separador
            
$msg .= $this->sep;
            echo 
$msg;
            
            if(
$this->logob_flush();
            
        }else if(
$this->veryverbose){
            if(
$irc){
                
print_r($mensaje);
            }else{
                
var_dump($mensaje);
            }

            if(
$this->log){
                
$msg ob_get_contents();
                
ob_flush();
            }
        }
        if(
$this->logfwrite($this->archivo$msg);
    }

    
/**
     * Escribe sobre el socket usado/Writes in the used socket
     * @param string $cadena Cadena a escribir/String to write
     * @param bool optional $crlf Define la escritura del CRLF en el protocolo IRC/Define the write of the CRLF in the protocol
     * @return void
     */
    
private function _out($cadena$crlf true){
        
$this->_msg($cadenafalse);
        
//Ignoramos los caracteres nulos
        
$cadena str_replace("\x00"''$cadena);
        
//Asignamos al último mensaje el mensaje que se enviará
        
$this->umsg $cadena;
        
$crlf $crlf "\r\n"'';
        
//El mensaje no puede superar los 512 caracteres, incluyendo CRLF
        
$cadena substr($cadena0510) . $crlf;
        if(
$this->socket)
            
fwrite($this->socket$cadena);
    }

    
/**
     * Genera cadenas aleatorias/Generate random strings
     * @param int $num El número de carácteres/The number of characters
     * @param string $caracteres Son los carácteres que se generarán/It is the characters that will be generated
     * @return Una cadena aleatoria entre UNO y VEINTE carácteres/A random string between ONE and TWENTY characters
     */
    
private function _caracteresAleatorios($num$caracteres '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'){
        
$strlen strlen($caracteres);
        if(
strval($num) < || strval($num) > 20$num 10;

        
$tmp '';
        for(
$i=0$i<$num$i++){
            
$tmp .= $caracteres[rand(0$strlen 1)];
        }
        return 
$tmp;
    }
}