libirc.php
changeset 30 2cfcd2801e5a
parent 21 d86ea89358ec
child 31 d75124700259
equal deleted inserted replaced
29:300f673fbbdc 30:2cfcd2801e5a
    51    * The function called when a private message is received.
    51    * The function called when a private message is received.
    52    * @var string
    52    * @var string
    53    */
    53    */
    54   
    54   
    55   private $privmsg_handler = false;
    55   private $privmsg_handler = false;
       
    56   
       
    57   /**
       
    58    * The function called when a timeout is suspected.
       
    59    * @var string
       
    60    */
       
    61   
       
    62   private $timeout_warning_handler = false;
       
    63   
       
    64   /**
       
    65    * The function called when a timeout is confirmed.
       
    66    * @var string
       
    67    */
       
    68   
       
    69   private $timeout_error_handler = false;
    56   
    70   
    57   /**
    71   /**
    58    * Switch to track if quitted or not. Helps avoid quitting the connection twice thus causing write errors.
    72    * Switch to track if quitted or not. Helps avoid quitting the connection twice thus causing write errors.
    59    * @var bool
    73    * @var bool
    60    * @access private
    74    * @access private
   103    * @param string Real name
   117    * @param string Real name
   104    * @param string NickServ password
   118    * @param string NickServ password
   105    * @param int Flags, defaults to 0.
   119    * @param int Flags, defaults to 0.
   106    */
   120    */
   107   
   121   
   108   public function connect($nick, $username, $realname, $pass, $flags = 0)
   122   public function connect($nick, $username, $realname, $pass = false, $flags = 0)
   109   {
   123   {
   110     // Init connection
   124     // Init connection
   111     $this->sock = fsockopen($this->host, $this->port);
   125     $this->sock = fsockopen($this->host, $this->port);
   112     if ( !$this->sock )
   126     if ( !$this->sock )
   113       throw new Exception('Could not make socket connection to host.');
   127       throw new Exception('Could not make socket connection to host.');
   133         $this->put("PONG :{$match[1]}\r\n");
   147         $this->put("PONG :{$match[1]}\r\n");
   134       }
   148       }
   135     }
   149     }
   136     
   150     
   137     // identify to nickserv
   151     // identify to nickserv
   138     $this->privmsg('NickServ', "IDENTIFY $pass");
   152     if ( $pass )
       
   153       $this->privmsg('NickServ', "IDENTIFY $pass");
   139     
   154     
   140     $this->nick = $nick;
   155     $this->nick = $nick;
   141     $this->user = $username;
   156     $this->user = $username;
       
   157     $this->quitted = false;
   142   }
   158   }
   143   
   159   
   144   /**
   160   /**
   145    * Writes some data to the socket, abstracted for debugging purposes.
   161    * Writes some data to the socket, abstracted for debugging purposes.
   146    * @param string Message to send, this should include a CRLF.
   162    * @param string Message to send, this should include a CRLF.
   162   /**
   178   /**
   163    * Reads from the socket...
   179    * Reads from the socket...
   164    * @return string
   180    * @return string
   165    */
   181    */
   166   
   182   
   167   public function get()
   183   public function get($timeout = 1)
   168   {
   184   {
   169     if ( !$this->sock )
   185     if ( !$this->sock )
   170     {
   186     {
   171       if ( defined('LIBIRC_DEBUG') )
   187       if ( defined('LIBIRC_DEBUG') )
   172         echo "<<< READ FAILED\n";
   188         echo "<<< READ FAILED\n";
   173       return false;
   189       return false;
   174     }
   190     }
   175     $out = fgets($this->sock, 4096);
   191     if ( ($c = stream_select($r = array($this->sock), $w = null, $e = null, $timeout)) !== false )
   176     if ( defined('LIBIRC_DEBUG') )
   192     {
   177       if ( !empty($out) )
   193       if ( $c > 0 )
   178         echo "<<< $out";
   194       {
   179     return $out;
   195         $out = fgets($this->sock, 4096);
       
   196         if ( defined('LIBIRC_DEBUG') )
       
   197           if ( !empty($out) )
       
   198             echo "<<< $out";
       
   199         return $out;
       
   200       }
       
   201     }
       
   202     return false;
   180   }
   203   }
   181   
   204   
   182   /**
   205   /**
   183    * Sends a message to a nick or channel.
   206    * Sends a message to a nick or channel.
   184    * @param string Nick or channel
   207    * @param string Nick or channel
   199    * The main event loop.
   222    * The main event loop.
   200    */
   223    */
   201   
   224   
   202   public function event_loop()
   225   public function event_loop()
   203   {
   226   {
   204     stream_set_timeout($this->sock, 0xFFFFFFFE);
   227     $timeout = 180;
   205     while ( $data = $this->get() )
   228     $timeout_warn = false;
   206     {
   229     while ( true )
   207       $data_trim = trim($data);
   230     {
       
   231       $data = $this->get($timeout);
       
   232       $data_trim = $data ? trim($data) : false;
       
   233       if ( empty($data_trim) )
       
   234       {
       
   235         if ( $timeout_warn )
       
   236         {
       
   237           // timeout confirmed :-/
       
   238           if ( $this->timeout_error_handler )
       
   239           {
       
   240             $result = @call_user_func($this->timeout_error_handler, $this);
       
   241             if ( $result == 'BREAK' )
       
   242               break;
       
   243           }
       
   244           $timeout = 180;
       
   245           $timeout_warn = false;
       
   246           continue;
       
   247         }
       
   248         // timeout suspected
       
   249         if ( $this->timeout_warning_handler )
       
   250         {
       
   251           $result = @call_user_func($this->timeout_warning_handler, $this);
       
   252           if ( $result == 'BREAK' )
       
   253             break;
       
   254         }
       
   255         // ping the server
       
   256         $this->put("PING :{$this->nick}\r\n");
       
   257         // set timeout lower to make reconnecting work as fast as possible
       
   258         $timeout = 10;
       
   259         $timeout_warn = true;
       
   260         continue;
       
   261       }
   208       $match = self::parse_message($data_trim);
   262       $match = self::parse_message($data_trim);
   209       if ( preg_match('/^PING :(.+?)$/', $data_trim, $pmatch) )
   263       if ( preg_match('/^PING :(.+?)$/', $data_trim, $pmatch) )
   210       {
   264       {
   211         $this->put("PONG :{$pmatch[1]}\r\n");
   265         $this->put("PONG :{$pmatch[1]}\r\n");
   212         eval(eb_fetch_hook('event_ping'));
   266         eval(eb_fetch_hook('event_ping'));
       
   267       }
       
   268       else if ( preg_match('/^:((?:[a-z0-9-]+\.)*[a-z0-9-]+) PONG \\1 :' . preg_quote($this->nick) .'/', $data_trim) )
       
   269       {
       
   270         $timeout = 180;
       
   271         $timeout_warn = false;
   213       }
   272       }
   214       else if ( $match )
   273       else if ( $match )
   215       {
   274       {
   216         // Received PRIVMSG or other mainstream action
   275         // Received PRIVMSG or other mainstream action
   217         if ( $match['action'] == 'JOIN' || $match['action'] == 'PART' )
   276         if ( $match['action'] == 'JOIN' || $match['action'] == 'PART' )
   267     $this->privmsg_handler = $func;
   326     $this->privmsg_handler = $func;
   268     return true;
   327     return true;
   269   }
   328   }
   270   
   329   
   271   /**
   330   /**
       
   331    * Changes the functions called when IRC connection timeouts occur.
       
   332    * @param string Function to call when a warning (no traffic within 3 minutes) occurs. If false, nothing will be called.
       
   333    * @param string Function to call if a ping timeout occurs. If false, nothing will be called.
       
   334    */
       
   335   
       
   336   function set_timeout_handlers($warn_func, $error_func)
       
   337   {
       
   338     $this->timeout_warning_handler = false;
       
   339     $this->timeout_error_handler = false;
       
   340     if ( function_exists($warn_func) )
       
   341     {
       
   342       $this->timeout_warning_handler = $warn_func;
       
   343     }
       
   344     if ( function_exists($error_func) )
       
   345     {
       
   346       $this->timeout_error_handler = $error_func;
       
   347     }
       
   348     return true;
       
   349   }
       
   350   
       
   351   /**
   272    * Parses a message line.
   352    * Parses a message line.
   273    * @param string Message text
   353    * @param string Message text
   274    * @return array Associative with keys: nick, user, host, action, target, message
   354    * @return array Associative with keys: nick, user, host, action, target, message
   275    */
   355    */
   276    
   356    
   307     $this->channels[strtolower($channel)] = $chan;
   387     $this->channels[strtolower($channel)] = $chan;
   308     return $chan;
   388     return $chan;
   309   }
   389   }
   310   
   390   
   311   /**
   391   /**
       
   392    * Changes the current nick.
       
   393    * @param string New nick.
       
   394    * @param string Password to authenticate to NickServ if needed.
       
   395    */
       
   396   
       
   397   public function change_nick($nick, $pass = false)
       
   398   {
       
   399     $this->put("NICK $nick\r\n");
       
   400     $this->nick = $nick;
       
   401     if ( $pass )
       
   402     {
       
   403       while ( $data = $this->get(3) )
       
   404       {
       
   405         if ( strstr($data, 'NickServ') )
       
   406         {
       
   407           $this->privmsg('NickServ', "IDENTIFY $pass");
       
   408           break;
       
   409         }
       
   410       }
       
   411     }
       
   412   }
       
   413   
       
   414   /**
   312    * Closes the connection and quits.
   415    * Closes the connection and quits.
   313    * @param string Optional part message
   416    * @param string Optional part message
   314    */
   417    */
   315   
   418   
   316   public function close($partmsg = false)
   419   public function close($partmsg = false)
   328       $channel->part($partmsg);
   431       $channel->part($partmsg);
   329     }
   432     }
   330     
   433     
   331     $this->put("QUIT\r\n");
   434     $this->put("QUIT\r\n");
   332     
   435     
   333     while ( $msg = $this->get() )
   436     while ( $msg = $this->get(1) )
   334     {
   437     {
   335       // Do nothing.
   438       // Do nothing.
   336     }
   439     }
   337     
   440     
   338     fclose($this->sock);
   441     fclose($this->sock);