Net_SmartIRC
[ class tree: Net_SmartIRC ] [ index: Net_SmartIRC ] [ all elements ]

Source for file SmartIRC.php

Documentation is available at SmartIRC.php

  1. <?php
  2. /**
  3.  * $Id: SmartIRC.php 253473 2008-02-21 18:58:34Z amir $
  4.  * $Revision: 253473 $
  5.  * $Author: amir $
  6.  * $Date: 2008-02-22 05:28:34 +1030 (Fri, 22 Feb 2008) $
  7.  *
  8.  * Net_SmartIRC
  9.  * This is a PHP class for communication with IRC networks,
  10.  * which conforms to the RFC 2812 (IRC protocol).
  11.  * It's an API that handles all IRC protocol messages.
  12.  * This class is designed for creating IRC bots, chats and show irc related info on webpages.
  13.  *
  14.  * Documenation, a HOWTO and examples are in SmartIRC included.
  15.  *
  16.  * Here you will find a service bot which I am also developing
  17.  * <http://cvs.meebey.net/atbs> and <http://cvs.meebey.net/phpbitch>
  18.  * Latest versions of Net_SmartIRC you will find on the project homepage
  19.  * or get it through PEAR since SmartIRC is an official PEAR package.
  20.  * See <http://pear.php.net/Net_SmartIRC>.
  21.  *
  22.  * Official Project Homepage: <http://sf.net/projects/phpsmartirc>
  23.  *
  24.  * Net_SmartIRC conforms to RFC 2812 (Internet Relay Chat: Client Protocol)
  25.  * 
  26.  * Copyright (c) 2002-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
  27.  * 
  28.  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  29.  * 
  30.  * This library is free software; you can redistribute it and/or
  31.  * modify it under the terms of the GNU Lesser General Public
  32.  * License as published by the Free Software Foundation; either
  33.  * version 2.1 of the License, or (at your option) any later version.
  34.  *
  35.  * This library is distributed in the hope that it will be useful,
  36.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  37.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  38.  * Lesser General Public License for more details.
  39.  *
  40.  * You should have received a copy of the GNU Lesser General Public
  41.  * License along with this library; if not, write to the Free Software
  42.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  43.  *
  44.  */
  45. // ------- PHP code ----------
  46. require_once 'SmartIRC/defines.php';
  47. define('SMARTIRC_VERSION''1.1.0-dev ($Revision: 253473 $)');
  48. define('SMARTIRC_VERSIONSTRING''Net_SmartIRC '.SMARTIRC_VERSION);
  49.  
  50. /**
  51.  * main SmartIRC class
  52.  *
  53.  * @package Net_SmartIRC
  54.  * @version 0.6.0-dev
  55.  * @author Mirco 'meebey' Bauer <mail@meebey.net>
  56.  * @access public
  57.  */
  58. {
  59.     /**
  60.      * @var resource 
  61.      * @access private
  62.      */
  63.     var $_socket;
  64.     
  65.     /**
  66.      * @var string 
  67.      * @access private
  68.      */
  69.     var $_address;
  70.     
  71.     /**
  72.      * @var integer 
  73.      * @access private
  74.      */
  75.     var $_port;
  76.     
  77.     /**
  78.      * @var string 
  79.      * @access private
  80.      */
  81.     var $_nick;
  82.     
  83.     /**
  84.      * @var string 
  85.      * @access private
  86.      */
  87.     var $_username;
  88.     
  89.     /**
  90.      * @var string 
  91.      * @access private
  92.      */
  93.     var $_realname;
  94.     
  95.     /**
  96.      * @var string 
  97.      * @access private
  98.      */
  99.     var $_usermode;
  100.     
  101.     /**
  102.      * @var string 
  103.      * @access private
  104.      */
  105.     var $_password;
  106.     
  107.     /**
  108.      * @var boolean 
  109.      * @access private
  110.      */
  111.     var $_state = false;
  112.     
  113.     /**
  114.      * @var array 
  115.      * @access private
  116.      */
  117.     var $_actionhandler = array();
  118.     
  119.     /**
  120.      * @var array 
  121.      * @access private
  122.      */
  123.     var $_timehandler = array();
  124.     
  125.     /**
  126.      * @var integer 
  127.      * @access private
  128.      */
  129.     var $_debug = SMARTIRC_DEBUG_NOTICE;
  130.     
  131.     /**
  132.      * @var array 
  133.      * @access private
  134.      */
  135.     var $_messagebuffer = array();
  136.     
  137.     /**
  138.      * @var integer 
  139.      * @access private
  140.      */
  141.     var $_messagebuffersize;
  142.     
  143.     /**
  144.      * @var boolean 
  145.      * @access private
  146.      */
  147.     var $_usesockets = false;
  148.     
  149.     /**
  150.      * @var integer 
  151.      * @access private
  152.      */
  153.     var $_receivedelay = 100;
  154.     
  155.     /**
  156.      * @var integer 
  157.      * @access private
  158.      */
  159.     var $_senddelay = 250;
  160.     
  161.     /**
  162.      * @var integer 
  163.      * @access private
  164.      */
  165.     var $_logdestination = SMARTIRC_STDOUT;
  166.     
  167.     /**
  168.      * @var resource 
  169.      * @access private
  170.      */
  171.     var $_logfilefp = 0;
  172.     
  173.     /**
  174.      * @var string 
  175.      * @access private
  176.      */
  177.     var $_logfile 'Net_SmartIRC.log';
  178.     
  179.     /**
  180.      * @var integer 
  181.      * @access private
  182.      */
  183.     var $_disconnecttime = 1000;
  184.     
  185.     /**
  186.      * @var boolean 
  187.      * @access private
  188.      */
  189.     var $_loggedin = false;
  190.     
  191.     /**
  192.      * @var boolean 
  193.      * @access private
  194.      */
  195.     var $_benchmark = false;
  196.     
  197.     /**
  198.      * @var integer 
  199.      * @access private
  200.      */
  201.     var $_benchmark_starttime;
  202.     
  203.     /**
  204.      * @var integer 
  205.      * @access private
  206.      */
  207.     var $_benchmark_stoptime;
  208.     
  209.     /**
  210.      * @var integer 
  211.      * @access private
  212.      */
  213.     var $_actionhandlerid = 0;
  214.     
  215.     /**
  216.      * @var integer 
  217.      * @access private
  218.      */
  219.     var $_timehandlerid = 0;
  220.     
  221.     /**
  222.      * @var array 
  223.      * @access private
  224.      */
  225.     var $_motd = array();
  226.     
  227.     /**
  228.      * @var array 
  229.      * @access private
  230.      */
  231.     var $_channels = array();
  232.     
  233.     /**
  234.      * @var boolean 
  235.      * @access private
  236.      */
  237.     var $_channelsyncing = false;
  238.     
  239.     /**
  240.      * @var array 
  241.      * @access private
  242.      */
  243.     var $_users = array();
  244.     
  245.     /**
  246.      * @var boolean 
  247.      * @access private
  248.      */
  249.     var $_usersyncing = false;
  250.     
  251.     /**
  252.      * Stores the path to the modules that can be loaded.
  253.      *
  254.      * @var string 
  255.      * @access privat
  256.      */
  257.     var $_modulepath '';
  258.     
  259.     /**
  260.      * Stores all objects of the modules.
  261.      *
  262.      * @var string 
  263.      * @access privat
  264.      */
  265.     var $_modules = array();
  266.     
  267.     /**
  268.      * @var string 
  269.      * @access private
  270.      */
  271.     var $_ctcpversion;
  272.     
  273.     /**
  274.      * @var mixed 
  275.      * @access private
  276.      */
  277.     var $_mintimer = false;
  278.     
  279.     /**
  280.      * @var integer 
  281.      * @access private
  282.      */
  283.     var $_maxtimer = 300000;
  284.     
  285.     /**
  286.      * @var integer 
  287.      * @access private
  288.      */
  289.     var $_txtimeout = 300;
  290.     
  291.     /**
  292.      * @var integer 
  293.      * @access private
  294.      */
  295.     var $_rxtimeout = 300;
  296.     
  297.     /**
  298.      * @var integer 
  299.      * @access private
  300.      */
  301.     var $_selecttimeout;
  302.     
  303.     /**
  304.      * @var integer 
  305.      * @access private
  306.      */
  307.     var $_lastrx;
  308.     
  309.     /**
  310.      * @var integer 
  311.      * @access private
  312.      */
  313.     var $_lasttx;
  314.     
  315.     /**
  316.      * @var boolean 
  317.      * @access private
  318.      */
  319.     var $_autoreconnect = false;
  320.     
  321.     /**
  322.      * @var integer 
  323.      * @access private
  324.      */
  325.     var $_reconnectdelay = 10000;
  326.  
  327.     /**
  328.      * @var boolean 
  329.      * @access private
  330.      */
  331.     var $_autoretry = false;
  332.  
  333.     /**
  334.      * @var integer 
  335.      * @access private
  336.      */
  337.     var $_autoretrymax = 5;
  338.  
  339.     /**
  340.      * @var integer 
  341.      * @access private
  342.      */
  343.     var $_autoretrycount = 0;
  344.     
  345.     /**
  346.      * @var boolean 
  347.      * @access private
  348.      */
  349.     var $_connectionerror = false;
  350.  
  351.     /**
  352.      * @var boolean 
  353.      * @access  private
  354.      */
  355.     var $_runasdaemon = false;
  356.     
  357.  
  358.     /**
  359.      * All IRC replycodes, the index is the replycode name.
  360.      *
  361.      * @see $SMARTIRC_replycodes
  362.      * @var array 
  363.      * @access public
  364.      */
  365.     var $replycodes;
  366.     
  367.     /**
  368.      * All numeric IRC replycodes, the index is the numeric replycode.
  369.      *
  370.      * @see $SMARTIRC_nreplycodes
  371.      * @var array 
  372.      * @access public
  373.      */
  374.     var $nreplycodes;
  375.     
  376.     /**
  377.      * Stores all channels in this array where we are joined, works only if channelsyncing is activated.
  378.      * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc)
  379.      * $irc->channel['#test']->users['meebey']->nick;
  380.      *
  381.      * @see setChannelSyncing()
  382.      * @see Net_SmartIRC_channel
  383.      * @see Net_SmartIRC_channeluser
  384.      * @var array 
  385.      * @access public
  386.      */
  387.     var $channel;
  388.     
  389.     /**
  390.      * Stores all users that had/have contact with us (channel/query/notice etc.), works only if usersyncing is activated.
  391.      * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc)
  392.      * $irc->user['meebey']->host;
  393.      *
  394.      * @see setUserSyncing()
  395.      * @see Net_SmartIRC_ircuser
  396.      * @var array 
  397.      * @access public
  398.      */
  399.     var $user;
  400.     
  401.     /**
  402.      * Constructor. Initiales the messagebuffer and "links" the replycodes from
  403.      * global into properties. Also some PHP runtime settings are configured.
  404.      *
  405.      * @access public
  406.      * @return void 
  407.      */
  408.     function Net_SmartIRC_base()
  409.     {
  410.         // precheck
  411.         $this->_checkPHPVersion();
  412.         
  413.         ob_implicit_flush(true);
  414.         @set_time_limit(0);
  415.         $this->_messagebuffer[SMARTIRC_CRITICAL= array();
  416.         $this->_messagebuffer[SMARTIRC_HIGH= array();
  417.         $this->_messagebuffer[SMARTIRC_MEDIUM= array();
  418.         $this->_messagebuffer[SMARTIRC_LOW= array();
  419.         
  420.         $this->replycodes = &$GLOBALS['SMARTIRC_replycodes'];
  421.         $this->nreplycodes = &$GLOBALS['SMARTIRC_nreplycodes'];
  422.         
  423.         // hack till PHP allows (PHP5) $object->somemethod($param)->memberofobject
  424.         $this->channel = &$this->_channels;
  425.         // another hack
  426.         $this->user = &$this->_users;
  427.         
  428.         if (isset($_SERVER['REQUEST_METHOD'])) {
  429.             // the script is called from a browser, lets set default log destination
  430.             // to SMARTIRC_BROWSEROUT (makes browser friendly output)
  431.             $this->setLogdestination(SMARTIRC_BROWSEROUT);
  432.         }
  433.     }
  434.     
  435.     /**
  436.      * Enables/disables the usage of real sockets.
  437.      *
  438.      * Enables/disables the usage of real sockets instead of fsocks
  439.      * (works only if your PHP build has loaded the PHP socket extension)
  440.      * Default: false
  441.      *
  442.      * @param bool $boolean 
  443.      * @return void 
  444.      * @access public
  445.      */
  446.     function setUseSockets($boolean)
  447.     {
  448.         if ($boolean === true{
  449.             if (@extension_loaded('sockets')) {
  450.                 $this->_usesockets = true;
  451.             else {
  452.                 $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: socket extension not loaded, trying to load it...'__FILE____LINE__);
  453.                 
  454.                 if (strtoupper(substr(PHP_OS0,3== 'WIN')) {
  455.                     $load_status @dl('php_sockets.dll');
  456.                 else {
  457.                     $load_status @dl('sockets.so');
  458.                 }
  459.  
  460.                 if ($load_status{
  461.                     $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: socket extension succesfully loaded'__FILE____LINE__);
  462.                     $this->_usesockets = true;
  463.                 else {
  464.                     $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: couldn\'t load the socket extension'__FILE____LINE__);
  465.                     $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: your PHP build doesn\'t support real sockets, will use fsocks instead'__FILE____LINE__);
  466.                     $this->_usesockets = false;
  467.                 }
  468.             }
  469.         else {
  470.             $this->_usesockets = false;
  471.         }
  472.     }
  473.     
  474.     /**
  475.      * Sets the level of debug messages.
  476.      *
  477.      * Sets the debug level (bitwise), useful for testing/developing your code.
  478.      * Here the list of all possible debug levels:
  479.      * SMARTIRC_DEBUG_NONE
  480.      * SMARTIRC_DEBUG_NOTICE
  481.      * SMARTIRC_DEBUG_CONNECTION
  482.      * SMARTIRC_DEBUG_SOCKET
  483.      * SMARTIRC_DEBUG_IRCMESSAGES
  484.      * SMARTIRC_DEBUG_MESSAGETYPES
  485.      * SMARTIRC_DEBUG_ACTIONHANDLER
  486.      * SMARTIRC_DEBUG_TIMEHANDLER
  487.      * SMARTIRC_DEBUG_MESSAGEHANDLER
  488.      * SMARTIRC_DEBUG_CHANNELSYNCING
  489.      * SMARTIRC_DEBUG_MODULES
  490.      * SMARTIRC_DEBUG_USERSYNCING
  491.      * SMARTIRC_DEBUG_ALL
  492.      *
  493.      * Default: SMARTIRC_DEBUG_NOTICE
  494.      *
  495.      * @see DOCUMENTATION
  496.      * @see SMARTIRC_DEBUG_NOTICE
  497.      * @param integer $level 
  498.      * @return void 
  499.      * @access public
  500.      */
  501.     function setDebug($level)
  502.     {
  503.         $this->_debug $level;
  504.     }
  505.     
  506.     /**
  507.      * Enables/disables the benchmark engine.
  508.      * 
  509.      * @param boolean $boolean 
  510.      * @return void 
  511.      * @access public
  512.      */
  513.     function setBenchmark($boolean)
  514.     {
  515.         if (is_bool($boolean)) {
  516.             $this->_benchmark $boolean;
  517.         else {
  518.             $this->_benchmark = false;
  519.         }
  520.     }
  521.     
  522.     /**
  523.      * Deprecated, use setChannelSyncing() instead!
  524.      *
  525.      * @deprecated
  526.      * @param boolean $boolean 
  527.      * @return void 
  528.      * @access public
  529.      */
  530.     function setChannelSynching($boolean)
  531.     {
  532.         $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: you are using setChannelSynching() which is a deprecated method, use setChannelSyncing() instead!'__FILE____LINE__);
  533.         $this->setChannelSyncing($boolean);
  534.     }
  535.     
  536.     /**
  537.      * Enables/disables channel syncing.
  538.      *
  539.      * Channel syncing means, all users on all channel we are joined are tracked in the
  540.      * channel array. This makes it very handy for botcoding.
  541.      * 
  542.      * @param boolean $boolean 
  543.      * @return void 
  544.      * @access public
  545.      */
  546.     function setChannelSyncing($boolean)
  547.     {
  548.         if (is_bool($boolean)) {
  549.             $this->_channelsyncing $boolean;
  550.         else {
  551.             $this->_channelsyncing = false;
  552.         }
  553.         
  554.         if ($this->_channelsyncing == true{
  555.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: Channel syncing enabled'__FILE____LINE__);
  556.         else {
  557.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: Channel syncing disabled'__FILE____LINE__);
  558.         }
  559.     }
  560.  
  561.     /**
  562.      * Enables/disables user syncing.
  563.      *
  564.      * User syncing means, all users we have or had contact with through channel, query or
  565.      * notice are tracked in the $irc->user array. This is very handy for botcoding.
  566.      *
  567.      * @param boolean $boolean 
  568.      * @return void 
  569.      * @access public
  570.      */
  571.     function setUserSyncing($boolean)
  572.     {
  573.         if (is_bool($boolean)) {
  574.             $this->_usersyncing $boolean;
  575.         else {
  576.             $this->_usersyncing = false;
  577.         }
  578.         
  579.         if ($this->_usersyncing == true{
  580.             $this->log(SMARTIRC_DEBUG_USERSYNCING'DEBUG_USERSYNCING: User syncing enabled'__FILE____LINE__);
  581.         else {
  582.             $this->log(SMARTIRC_DEBUG_USERSYNCING'DEBUG_USERSYNCING: User syncing disabled'__FILE____LINE__);
  583.         }
  584.     }
  585.     
  586.     /**
  587.      * Sets the CTCP version reply string.
  588.      * 
  589.      * @param string $versionstring 
  590.      * @return void 
  591.      * @access public
  592.      */
  593.     function setCtcpVersion($versionstring)
  594.     {
  595.         $this->_ctcpversion $versionstring;
  596.     }
  597.     
  598.     /**
  599.      * Sets the destination of all log messages.
  600.      *
  601.      * Sets the destination of log messages.
  602.      * $type can be:
  603.      * SMARTIRC_FILE for saving the log into a file
  604.      * SMARTIRC_STDOUT for echoing the log to stdout
  605.      * SMARTIRC_SYSLOG for sending the log to the syslog
  606.      * Default: SMARTIRC_STDOUT
  607.      *
  608.      * @see SMARTIRC_STDOUT
  609.      * @param integer $type must be on of the constants
  610.      * @return void 
  611.      * @access public
  612.      */
  613.     function setLogdestination($type)
  614.     {
  615.         switch ($type{
  616.             case SMARTIRC_FILE:
  617.             case SMARTIRC_STDOUT:
  618.             case SMARTIRC_SYSLOG:
  619.             case SMARTIRC_BROWSEROUT:
  620.             case SMARTIRC_NONE:
  621.                 $this->_logdestination $type;
  622.             break;
  623.             default:
  624.                 $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: unknown logdestination type ('.$type.'), will use STDOUT instead'__FILE____LINE__);
  625.                 $this->_logdestination SMARTIRC_STDOUT;
  626.         }
  627.     }
  628.     
  629.     /**
  630.      * Sets the file for the log if the destination is set to file.
  631.      *
  632.      * Sets the logfile, if {@link setLogdestination logdestination} is set to SMARTIRC_FILE.
  633.      * This should be only used with full path!
  634.      *
  635.      * @param string $file 
  636.      * @return void 
  637.      * @access public
  638.      */
  639.     function setLogfile($file)
  640.     {
  641.         $this->_logfile $file;
  642.     }
  643.     
  644.     /**
  645.      * Sets the delaytime before closing the socket when disconnect.
  646.      *
  647.      * @param integer $milliseconds 
  648.      * @return void 
  649.      * @access public
  650.      */
  651.     function setDisconnecttime($milliseconds)
  652.     {
  653.         if (is_integer($milliseconds&& $milliseconds >= 100{
  654.             $this->_disconnecttime $milliseconds;
  655.         else {
  656.             $this->_disconnecttime = 100;
  657.         }
  658.     }
  659.     
  660.     /**
  661.      * Sets the delaytime before attempting reconnect.
  662.      * Value of 0 disables the delay entirely.
  663.      *
  664.      * @param integer $milliseconds 
  665.      * @return void 
  666.      * @access public
  667.      */
  668.     function setReconnectdelay($milliseconds)
  669.     {
  670.         if (is_integer($milliseconds)) {
  671.             $this->_reconnectdelay $milliseconds;
  672.         else {
  673.             $this->_reconnectdelay = 10000;
  674.         }
  675.     }
  676.  
  677.     /**
  678.      * Sets the delay for receiving data from the IRC server.
  679.      *
  680.      * Sets the delaytime between messages that are received, this reduces your CPU load.
  681.      * Don't set this too low (min 100ms).
  682.      * Default: 100
  683.      *
  684.      * @param integer $milliseconds 
  685.      * @return void 
  686.      * @access public
  687.      */
  688.     function setReceivedelay($milliseconds)
  689.     {
  690.         if (is_integer($milliseconds&& $milliseconds >= 100{
  691.             $this->_receivedelay $milliseconds;
  692.         else {
  693.             $this->_receivedelay = 100;
  694.         }
  695.     }
  696.     
  697.     /**
  698.      * Sets the delay for sending data to the IRC server.
  699.      *
  700.      * Sets the delaytime between messages that are sent, because IRC servers doesn't like floods.
  701.      * This will avoid sending your messages too fast to the IRC server.
  702.      * Default: 250
  703.      *
  704.      * @param integer $milliseconds 
  705.      * @return void 
  706.      * @access public
  707.      */
  708.     function setSenddelay($milliseconds)
  709.     {
  710.         if (is_integer($milliseconds)) {
  711.             $this->_senddelay $milliseconds;
  712.         else {
  713.             $this->_senddelay = 250;
  714.         }
  715.     }
  716.     
  717.     /**
  718.      * Enables/disables autoreconnecting.
  719.      * 
  720.      * @param boolean $boolean 
  721.      * @return void 
  722.      * @access public
  723.      */
  724.     function setAutoReconnect($boolean)
  725.     {
  726.         if (is_bool($boolean)) {
  727.             $this->_autoreconnect $boolean;
  728.         else {
  729.             $this->_autoreconnect = false;
  730.         }
  731.     }
  732.     
  733.     /**
  734.      * Enables/disables autoretry for connecting to a server.
  735.      * 
  736.      * @param boolean $boolean 
  737.      * @return void 
  738.      * @access public
  739.      */
  740.     function setAutoRetry($boolean)
  741.     {
  742.         if (is_bool($boolean)) {
  743.             $this->_autoretry $boolean;
  744.         else {
  745.             $this->_autoretry = false;
  746.         }
  747.     }
  748.  
  749.     /**
  750.      * Sets the maximum number of attempts to connect to a server
  751.      * before giving up.
  752.      *
  753.      * @param integer $autoretrymax 
  754.      * @return void 
  755.      * @access public
  756.      */
  757.     function setAutoRetryMax($autoretrymax)
  758.     {
  759.         if (is_integer($autoretrymax)) {
  760.             $this->_autoretrymax $autoretrymax;
  761.         else {
  762.             $this->_autoretrymax = 5;
  763.         }
  764.     }
  765.  
  766.     /**
  767.      * Sets the receive timeout.
  768.      *
  769.      * If the timeout occurs, the connection will be reinitialized
  770.      * Default: 300 seconds
  771.      *
  772.      * @param integer $seconds 
  773.      * @return void 
  774.      * @access public
  775.      */
  776.     function setReceiveTimeout($seconds)
  777.     {
  778.         if (is_integer($seconds)) {
  779.             $this->_rxtimeout $seconds;
  780.         else {
  781.             $this->_rxtimeout = 300;
  782.         }
  783.     }
  784.     
  785.     /**
  786.      * Sets the transmit timeout.
  787.      *
  788.      * If the timeout occurs, the connection will be reinitialized
  789.      * Default: 300 seconds
  790.      *
  791.      * @param integer $seconds 
  792.      * @return void 
  793.      * @access public
  794.      */
  795.     function setTransmitTimeout($seconds)
  796.     {
  797.         if (is_integer($seconds)) {
  798.             $this->_txtimeout $seconds;
  799.         else {
  800.             $this->_txtimeout = 300;
  801.         }
  802.     }
  803.     
  804.     /**
  805.      * Sets the paths for the modules.
  806.      *
  807.      * @param integer $path 
  808.      * @return void 
  809.      * @access public
  810.      */
  811.     function setModulepath($path)
  812.     {
  813.         $this->_modulepath $path;
  814.     }
  815.  
  816.     /**
  817.      * Sets wheter the script should be run as a daemon or not
  818.      * ( actually disables/enables ignore_user_abort() )
  819.      *
  820.      * @param boolean $boolean 
  821.      * @return void 
  822.      * @access public
  823.      */
  824.     function setRunAsDaemon($boolean)
  825.     {
  826.         if ($boolean === true{
  827.             $this->_runasdaemon = true;
  828.             ingore_user_abort(true);
  829.         else {
  830.             $this->_runasdaemon = false;
  831.         }
  832.     }
  833.     
  834.     /**
  835.      * Starts the benchmark (sets the counters).
  836.      *
  837.      * @return void 
  838.      * @access public
  839.      */
  840.     function startBenchmark()
  841.     {
  842.         $this->_benchmark_starttime $this->_microint();
  843.         $this->log(SMARTIRC_DEBUG_NOTICE'benchmark started'__FILE____LINE__);
  844.     }
  845.     
  846.     /**
  847.      * Stops the benchmark and displays the result.
  848.      *
  849.      * @return void 
  850.      * @access public
  851.      */
  852.     function stopBenchmark()
  853.     {
  854.         $this->_benchmark_stoptime $this->_microint();
  855.         $this->log(SMARTIRC_DEBUG_NOTICE'benchmark stopped'__FILE____LINE__);
  856.         
  857.         if ($this->_benchmark{
  858.             $this->showBenchmark();
  859.         }
  860.     }
  861.     
  862.     /**
  863.      * Shows the benchmark result.
  864.      *
  865.      * @return void 
  866.      * @access public
  867.      */
  868.     function showBenchmark()
  869.     {
  870.         $this->log(SMARTIRC_DEBUG_NOTICE'benchmark time: '.((float)$this->_benchmark_stoptime-(float)$this->_benchmark_starttime)__FILE____LINE__);
  871.     }
  872.     
  873.     /**
  874.      * Adds an entry to the log.
  875.      *
  876.      * Adds an entry to the log with Linux style log format.
  877.      * Possible $level constants (can also be combined with "|"s)
  878.      * SMARTIRC_DEBUG_NONE
  879.      * SMARTIRC_DEBUG_NOTICE
  880.      * SMARTIRC_DEBUG_CONNECTION
  881.      * SMARTIRC_DEBUG_SOCKET
  882.      * SMARTIRC_DEBUG_IRCMESSAGES
  883.      * SMARTIRC_DEBUG_MESSAGETYPES
  884.      * SMARTIRC_DEBUG_ACTIONHANDLER
  885.      * SMARTIRC_DEBUG_TIMEHANDLER
  886.      * SMARTIRC_DEBUG_MESSAGEHANDLER
  887.      * SMARTIRC_DEBUG_CHANNELSYNCING
  888.      * SMARTIRC_DEBUG_MODULES
  889.      * SMARTIRC_DEBUG_USERSYNCING
  890.      * SMARTIRC_DEBUG_ALL
  891.      *
  892.      * @see SMARTIRC_DEBUG_NOTICE
  893.      * @param integer $level bit constants (SMARTIRC_DEBUG_*)
  894.      * @param string $entry the new log entry
  895.      * @return void 
  896.      * @access public
  897.      */
  898.     function log($level$entry$file = null$line = null)
  899.     {
  900.         // prechecks
  901.         if (!(is_integer($level)) ||
  902.             !($level SMARTIRC_DEBUG_ALL)) {
  903.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: invalid log level passed to log() ('.$level.')'__FILE____LINE__);
  904.             return;
  905.         }
  906.         
  907.         if (!($level $this->_debug||
  908.              ($this->_logdestination == SMARTIRC_NONE)) {
  909.             return;
  910.         }
  911.         
  912.         if (substr($entry-1!= "\n"{
  913.             $entry .= "\n";
  914.         }
  915.         
  916.         if ($file !== null &&
  917.             $line !== null{
  918.             $file basename($file);
  919.             $entry $file.'('.$line.') '.$entry;
  920.         else {
  921.             $entry 'unknown(0) '.$entry;
  922.         }
  923.         
  924.         $formatedentry date('M d H:i:s ').$entry;
  925.         switch ($this->_logdestination{
  926.             case SMARTIRC_STDOUT:
  927.                 echo $formatedentry;
  928.                 flush();
  929.             break;
  930.             case SMARTIRC_BROWSEROUT:
  931.                 echo '<pre>'.htmlentities($formatedentry).'</pre>';
  932.             break;
  933.             case SMARTIRC_FILE:
  934.                 if (!is_resource($this->_logfilefp)) {
  935.                     if ($this->_logfilefp === null{
  936.                         // we reconncted and don't want to destroy the old log entries
  937.                         $this->_logfilefp fopen($this->_logfile,'a');
  938.                     else {
  939.                         $this->_logfilefp fopen($this->_logfile,'w');
  940.                     }
  941.                 }
  942.                 fwrite($this->_logfilefp$formatedentry);
  943.                 fflush($this->_logfilefp);
  944.             break;
  945.             case SMARTIRC_SYSLOG:
  946.                 define_syslog_variables();
  947.                 if (!is_int($this->_logfilefp)) {
  948.                     $this->_logfilefp openlog('Net_SmartIRC'LOG_NDELAYLOG_DAEMON);
  949.                 }
  950.                 syslog(LOG_INFO$entry);
  951.             break;
  952.         }
  953.     }
  954.     
  955.     /**
  956.      * Returns the full motd.
  957.      *
  958.      * @return array 
  959.      * @access public
  960.      */
  961.     function getMotd()
  962.     {
  963.         return $this->_motd;
  964.     }
  965.     
  966.     /**
  967.      * Returns the usermode.
  968.      *
  969.      * @return string 
  970.      * @access public
  971.      */
  972.     function getUsermode()
  973.     {
  974.         return $this->_usermode;
  975.     }
  976.     
  977.     /**
  978.      * Returns a reference to the channel object of the specified channelname.
  979.      *
  980.      * @param string $channelname 
  981.      * @return object 
  982.      * @access public
  983.      */
  984.     function &getChannel($channelname)
  985.     {
  986.         if ($this->_channelsyncing != true{
  987.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: getChannel() is called and the required Channel Syncing is not activated!'__FILE____LINE__);
  988.             return false;
  989.         }
  990.         
  991.         if ($this->isJoined($channelname)) {
  992.             return $this->_channels[strtolower($channelname)];
  993.         else {
  994.             return false;
  995.         }
  996.     }
  997.     
  998.     /**
  999.      * Returns a reference to the user object for the specified username and channelname.
  1000.      *
  1001.      * @param string $channelname 
  1002.      * @param string $username 
  1003.      * @return object 
  1004.      * @access public
  1005.      */
  1006.     function &getUser($channelname$username)
  1007.     {
  1008.         if ($this->_channelsyncing != true{
  1009.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: getUser() is called and the required Channel Syncing is not activated!'__FILE____LINE__);
  1010.             return false;
  1011.         }
  1012.         
  1013.         if ($this->isJoined($channelname$username)) {
  1014.             return $this->_channels[strtolower($channelname)]->users[strtolower($username)];
  1015.         else {
  1016.             return false;
  1017.         }
  1018.     }
  1019.  
  1020.     /**
  1021.      * Creates the sockets and connects to the IRC server on the given port.
  1022.      *
  1023.      * @param string $address 
  1024.      * @param integer $port 
  1025.      * @return boolean 
  1026.      * @access public
  1027.      */
  1028.     function connect($address$port)
  1029.     {
  1030.         $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: connecting'__FILE____LINE__);
  1031.         $this->_address $address;
  1032.         $this->_port $port;
  1033.         
  1034.         if ($this->_usesockets == true{
  1035.             $this->log(SMARTIRC_DEBUG_SOCKET'DEBUG_SOCKET: using real sockets'__FILE____LINE__);
  1036.             $this->_socket = socket_create(AF_INETSOCK_STREAMSOL_TCP);
  1037.             $result = socket_connect($this->_socket$this->_address$this->_port);
  1038.         else {
  1039.             $this->log(SMARTIRC_DEBUG_SOCKET'DEBUG_SOCKET: using fsockets'__FILE____LINE__);
  1040.             $result fsockopen($this->_address$this->_port$errno$errstr);
  1041.         }
  1042.         
  1043.         if ($result === false{
  1044.             if ($this->_usesockets == true{
  1045.                 $error = socket_strerror(socket_last_error($this->_socket));
  1046.             else {
  1047.                 $error $errstr.' ('.$errno.')';
  1048.             }
  1049.             
  1050.             $error_msg 'couldn\'t connect to "'.$address.'" reason: "'.$error.'"';
  1051.             $this->log(SMARTIRC_DEBUG_NOTICE'DEBUG_NOTICE: '.$error_msg__FILE____LINE__);
  1052.             // TODO! needs to be return value
  1053.             $this->throwError($error_msg);
  1054.             
  1055.             if (($this->_autoretry == true&&
  1056.                 ($this->_autoretrycount $this->_autoretrymax)) {
  1057.                  $this->_delayReconnect();
  1058.                  $this->_autoretrycount++;
  1059.                  $this->reconnect();
  1060.             else {
  1061.                 return false;
  1062.             }
  1063.         else {
  1064.             $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: connected'__FILE____LINE__);
  1065.             $this->_autoretrycount = 0;
  1066.             $this->_connectionerror = false;
  1067.             
  1068.             if ($this->_usesockets != true{
  1069.                 $this->_socket $result;
  1070.                 $this->log(SMARTIRC_DEBUG_SOCKET'DEBUG_SOCKET: activating nonblocking fsocket mode'__FILE____LINE__);
  1071.                 socket_set_blocking($this->_socketfalse);
  1072.             }
  1073.         }
  1074.         
  1075.         $this->_lastrx time();
  1076.         $this->_lasttx $this->_lastrx;
  1077.         $this->_updatestate();
  1078.         
  1079.         return $result !== false;
  1080.     }
  1081.     
  1082.     /**
  1083.      * Disconnects from the IRC server nicely with a QUIT or just destroys the socket.
  1084.      *
  1085.      * Disconnects from the IRC server in the given quickness mode.
  1086.      * $quickdisconnect:
  1087.      * true, just close the socket
  1088.      * false, send QUIT and wait {@link $_disconnectime $_disconnectime} before closing the socket
  1089.      *
  1090.      * @param boolean $quickdisconnect default: false
  1091.      * @return boolean 
  1092.      * @access public
  1093.      */
  1094.     function disconnect($quickdisconnect = false)
  1095.     {
  1096.         if ($this->_state(== SMARTIRC_STATE_CONNECTED{
  1097.             if ($quickdisconnect == false{
  1098.                 $this->_send('QUIT'SMARTIRC_CRITICAL);
  1099.                 usleep($this->_disconnecttime*1000);
  1100.             }
  1101.             
  1102.             if ($this->_usesockets == true{
  1103.                 @socket_shutdown($this->_socket);
  1104.                 @socket_close($this->_socket);
  1105.             else {
  1106.                 fclose($this->_socket);
  1107.             }
  1108.             
  1109.             $this->_updatestate();
  1110.             $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: disconnected'__FILE____LINE__);
  1111.         else {
  1112.             return false;
  1113.         }
  1114.         
  1115.         if ($this->_channelsyncing == true{
  1116.             // let's clean our channel array
  1117.             $this->_channels = array();
  1118.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: cleaned channel array'__FILE____LINE__);
  1119.         }
  1120.         
  1121.         if ($this->_usersyncing == true{
  1122.             // let's clean our user array
  1123.             $this->_users = array();
  1124.             $this->log(SMARTIRC_DEBUG_USERSYNCING'DEBUG_USERSYNCING: cleaned user array'__FILE____LINE__);
  1125.         }
  1126.         
  1127.         if ($this->_logdestination == SMARTIRC_FILE{
  1128.             fclose($this->_logfilefp);
  1129.             $this->_logfilefp = null;
  1130.         else if ($this->_logdestination == SMARTIRC_SYSLOG{
  1131.             closelog();
  1132.         }
  1133.         
  1134.         return true;
  1135.     }
  1136.     
  1137.     /**
  1138.      * Reconnects to the IRC server with the same login info,
  1139.      * it also rejoins the channels
  1140.      *
  1141.      * @return void 
  1142.      * @access public
  1143.      */
  1144.     function reconnect()
  1145.     {
  1146.         $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: reconnecting...'__FILE____LINE__);
  1147.         
  1148.         // remember in which channels we are joined
  1149.         $channels = array();
  1150.         foreach ($this->_channels as $value{
  1151.             if (empty($value->key)) {
  1152.                 $channels[= array('name' => $value->name);
  1153.             else {
  1154.                 $channels[= array('name' => $value->name'key' => $value->key);
  1155.             }
  1156.         }
  1157.         
  1158.         $this->disconnect(true);
  1159.         $this->connect($this->_address$this->_port);
  1160.         $this->login($this->_nick$this->_realname$this->_usermode$this->_username$this->_password);
  1161.         
  1162.         // rejoin the channels
  1163.         foreach ($channels as $value{
  1164.             if (isset($value['key'])) {
  1165.                 $this->join($value['name']$value['key']);
  1166.             else {
  1167.                 $this->join($value['name']);
  1168.             }
  1169.         }
  1170.     }
  1171.     
  1172.     /**
  1173.      * login and register nickname on the IRC network
  1174.      *
  1175.      * Registers the nickname and user information on the IRC network.
  1176.      *
  1177.      * @param string $nick 
  1178.      * @param string $realname 
  1179.      * @param integer $usermode 
  1180.      * @param string $username 
  1181.      * @param string $password 
  1182.      * @return void 
  1183.      * @access public
  1184.      */
  1185.     function login($nick$realname$usermode = 0$username = null$password = null)
  1186.     {
  1187.         $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: logging in'__FILE____LINE__);
  1188.         
  1189.         $this->_nick str_replace(' '''$nick);
  1190.         $this->_realname $realname;
  1191.         
  1192.         if ($username !== null{
  1193.             $this->_username str_replace(' '''$username);
  1194.         else {
  1195.             $this->_username str_replace(' '''exec('whoami'));
  1196.         }
  1197.         
  1198.         if ($password !== null{
  1199.             $this->_password $password;
  1200.             $this->_send('PASS '.$this->_passwordSMARTIRC_CRITICAL);
  1201.         }
  1202.         
  1203.         if (!is_numeric($usermode)) {
  1204.             $this->log(SMARTIRC_DEBUG_NOTICE'DEBUG_NOTICE: login() usermode ('.$usermode.') is not valid, will use 0 instead'__FILE____LINE__);
  1205.             $usermode = 0;
  1206.         }
  1207.         
  1208.         $this->_send('NICK '.$this->_nickSMARTIRC_CRITICAL);
  1209.         $this->_send('USER '.$this->_username.' '.$usermode.' '.SMARTIRC_UNUSED.' :'.$this->_realnameSMARTIRC_CRITICAL);
  1210.     }
  1211.     
  1212.     // </IRC methods>
  1213.     
  1214.     /**
  1215.      * checks if the passed nickname is our own nickname
  1216.      *
  1217.      * @param string $nickname 
  1218.      * @return boolean 
  1219.      * @access public
  1220.      */
  1221.     function isMe($nickname)
  1222.     {
  1223.         if ($nickname == $this->_nick{
  1224.             return true;
  1225.         else {
  1226.             return false;
  1227.         }
  1228.     }
  1229.     
  1230.     /**
  1231.      * checks if we or the given user is joined to the specified channel and returns the result
  1232.      * ChannelSyncing is required for this.
  1233.      *
  1234.      * @see setChannelSyncing
  1235.      * @param string $channel 
  1236.      * @param string $nickname 
  1237.      * @return boolean 
  1238.      * @access public
  1239.      */
  1240.     function isJoined($channel$nickname = null)
  1241.     {
  1242.         if ($this->_channelsyncing != true{
  1243.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: isJoined() is called and the required Channel Syncing is not activated!'__FILE____LINE__);
  1244.             return false;
  1245.         }
  1246.         
  1247.         if ($nickname === null{
  1248.             $nickname $this->_nick;
  1249.         }
  1250.         
  1251.         if (isset($this->_channels[strtolower($channel)]->users[strtolower($nickname)])) {
  1252.             return true;
  1253.         }
  1254.         
  1255.         return false;
  1256.     }
  1257.     
  1258.     /**
  1259.      * Checks if we or the given user is opped on the specified channel and returns the result.
  1260.      * ChannelSyncing is required for this.
  1261.      *
  1262.      * @see setChannelSyncing
  1263.      * @param string $channel 
  1264.      * @param string $nickname 
  1265.      * @return boolean 
  1266.      * @access public
  1267.      */
  1268.     function isOpped($channel$nickname = null)
  1269.     {
  1270.         if ($this->_channelsyncing != true{
  1271.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: isOpped() is called and the required Channel Syncing is not activated!'__FILE____LINE__);
  1272.             return false;
  1273.         }
  1274.         
  1275.         if ($nickname === null{
  1276.             $nickname $this->_nick;
  1277.         }
  1278.         
  1279.         if ($this->isJoined($channel$nickname)) {
  1280.             if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->op{
  1281.                 return true;
  1282.             }
  1283.         }
  1284.         
  1285.         return false;
  1286.     }
  1287.     
  1288.     /**
  1289.      * Checks if we or the given user is voiced on the specified channel and returns the result.
  1290.      * ChannelSyncing is required for this.
  1291.      *
  1292.      * @see setChannelSyncing
  1293.      * @param string $channel 
  1294.      * @param string $nickname 
  1295.      * @return boolean 
  1296.      * @access public
  1297.      */
  1298.     function isVoiced($channel$nickname = null)
  1299.     {
  1300.         if ($this->_channelsyncing != true{
  1301.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: isVoiced() is called and the required Channel Syncing is not activated!'__FILE____LINE__);
  1302.             return false;
  1303.         }
  1304.         
  1305.         if ($nickname === null{
  1306.             $nickname $this->_nick;
  1307.         }
  1308.         
  1309.         if ($this->isJoined($channel$nickname)) {
  1310.             if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->voice{
  1311.                 return true;
  1312.             }
  1313.         }
  1314.         
  1315.         return false;
  1316.     }
  1317.     
  1318.     /**
  1319.      * Checks if the hostmask is on the specified channel banned and returns the result.
  1320.      * ChannelSyncing is required for this.
  1321.      *
  1322.      * @see setChannelSyncing
  1323.      * @param string $channel 
  1324.      * @param string $hostmask 
  1325.      * @return boolean 
  1326.      * @access public
  1327.      */
  1328.     function isBanned($channel$hostmask)
  1329.     {
  1330.         if ($this->_channelsyncing != true{
  1331.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: isBanned() is called and the required Channel Syncing is not activated!'__FILE____LINE__);
  1332.             return false;
  1333.         }
  1334.         
  1335.         if ($this->isJoined($channel)) {
  1336.             $result array_search($hostmask$this->_channels[strtolower($channel)]->bans);
  1337.             
  1338.             if ($result !== false{
  1339.                 return true;
  1340.             }
  1341.         }
  1342.         
  1343.         return false;
  1344.     }
  1345.     
  1346.     /**
  1347.      * goes into receive mode
  1348.      *
  1349.      * Goes into receive and idle mode. Only call this if you want to "spawn" the bot.
  1350.      * No further lines of PHP code will be processed after this call, only the bot methods!
  1351.      *
  1352.      * @return boolean 
  1353.      * @access public
  1354.      */
  1355.     function listen()
  1356.     {
  1357.         while ($this->_state(== SMARTIRC_STATE_CONNECTED{
  1358.             $this->listenOnce();
  1359.         }
  1360.             
  1361.         return false;
  1362.     }
  1363.     
  1364.     /**
  1365.      * goes into receive mode _only_ for one pass
  1366.      *
  1367.      * Goes into receive mode. It will return when one pass is complete.
  1368.      * Use this when you want to connect to multiple IRC servers.
  1369.      *
  1370.      * @return boolean 
  1371.      * @access public
  1372.      */
  1373.     function listenOnce()
  1374.     {
  1375.         if ($this->_state(== SMARTIRC_STATE_CONNECTED{
  1376.             $this->_rawreceive();
  1377.             if ($this->_connectionerror{
  1378.                 if ($this->_autoreconnect{
  1379.                     $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: connection error detected, will reconnect!'__FILE____LINE__);
  1380.                     $this->reconnect();
  1381.                 else {
  1382.                     $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: connection error detected, will disconnect!'__FILE____LINE__);
  1383.                     $this->disconnect();
  1384.                 }
  1385.             }
  1386.             return true;
  1387.         else {
  1388.             return false;
  1389.         }
  1390.     }
  1391.     
  1392.     /**
  1393.      * waits for a special message type and puts the answer in $result
  1394.      *
  1395.      * Creates a special actionhandler for that given TYPE and returns the answer.
  1396.      * This will only receive the requested type, immediately quit and disconnect from the IRC server.
  1397.      * Made for showing IRC statistics on your homepage, or other IRC related information.
  1398.      *
  1399.      * @param integer $messagetype see in the documentation 'Message Types'
  1400.      * @return array answer from the IRC server for this $messagetype
  1401.      * @access public
  1402.      */
  1403.     function listenFor($messagetype)
  1404.     {
  1405.         $listenfor &new Net_SmartIRC_listenfor();
  1406.         $this->registerActionhandler($messagetype'.*'$listenfor'handler');
  1407.         $this->listen();
  1408.         $result $listenfor->result;
  1409.         
  1410.         if (isset($listenfor)) {
  1411.             unset($listenfor);
  1412.         }
  1413.         
  1414.         return $result;
  1415.     }
  1416.     
  1417.     /**
  1418.      * registers a new actionhandler and returns the assigned id
  1419.      *
  1420.      * Registers an actionhandler in Net_SmartIRC for calling it later.
  1421.      * The actionhandler id is needed for unregistering the actionhandler.
  1422.      *
  1423.      * @see example.php
  1424.      * @param integer $handlertype bits constants, see in this documentation Message Types
  1425.      * @param string $regexhandler the message that has to be in the IRC message in regex syntax
  1426.      * @param object $object a reference to the objects of the method
  1427.      * @param string $methodname the methodname that will be called when the handler happens
  1428.      * @return integer assigned actionhandler id
  1429.      * @access public
  1430.      */
  1431.     function registerActionhandler($handlertype$regexhandler&$object$methodname)
  1432.     {
  1433.         // precheck
  1434.         if (!$this->_isValidType($handlertype)) {
  1435.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: passed invalid handlertype to registerActionhandler()'__FILE____LINE__);
  1436.             return false;
  1437.         }
  1438.         
  1439.         $id $this->_actionhandlerid++;
  1440.         $newactionhandler &new Net_SmartIRC_actionhandler();
  1441.         
  1442.         $newactionhandler->id = $id;
  1443.         $newactionhandler->type = $handlertype;
  1444.         $newactionhandler->message = $regexhandler;
  1445.         $newactionhandler->object = &$object;
  1446.         $newactionhandler->method = $methodname;
  1447.         
  1448.         $this->_actionhandler[&$newactionhandler;
  1449.         $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: actionhandler('.$id.') registered'__FILE____LINE__);
  1450.         return $id;
  1451.     }
  1452.     
  1453.     /**
  1454.      * unregisters an existing actionhandler
  1455.      *
  1456.      * @param integer $handlertype 
  1457.      * @param string $regexhandler 
  1458.      * @param object $object 
  1459.      * @param string $methodname 
  1460.      * @return boolean 
  1461.      * @access public
  1462.      */
  1463.     function unregisterActionhandler($handlertype$regexhandler&$object$methodname)
  1464.     {
  1465.         // precheck
  1466.         if (!$this->_isValidType($handlertype)) {
  1467.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: passed invalid handlertype to unregisterActionhandler()'__FILE____LINE__);
  1468.             return false;
  1469.         }
  1470.         
  1471.         $handler &$this->_actionhandler;
  1472.         $handlercount count($handler);
  1473.         
  1474.         for ($i = 0; $i $handlercount$i++{
  1475.             $handlerobject &$handler[$i];
  1476.                         
  1477.             if ($handlerobject->type == $handlertype &&
  1478.                 $handlerobject->message == $regexhandler &&
  1479.                 $handlerobject->method == $methodname{
  1480.                 
  1481.                 $id $handlerobject->id;
  1482.                 
  1483.                 if (isset($this->_actionhandler[$i])) {
  1484.                     unset($this->_actionhandler[$i]);
  1485.                 }
  1486.                 
  1487.                 $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered'__FILE____LINE__);
  1488.                 $this->_reorderactionhandler();
  1489.                 return true;
  1490.             }
  1491.         }
  1492.         
  1493.         $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: could not find actionhandler type: "'.$handlertype.'" message: "'.$regexhandler.'" method: "'.$methodname.'" from object "'.get_class($object).'" _not_ unregistered'__FILE____LINE__);
  1494.         return false;
  1495.     }
  1496.     
  1497.     /**
  1498.      * unregisters an existing actionhandler via the id
  1499.      *
  1500.      * @param integer $id 
  1501.      * @return boolean 
  1502.      * @access public
  1503.      */
  1504.     function unregisterActionid($id)
  1505.     {
  1506.         $handler &$this->_actionhandler;
  1507.         $handlercount count($handler);
  1508.         for ($i = 0; $i $handlercount$i++{
  1509.             $handlerobject &$handler[$i];
  1510.                         
  1511.             if ($handlerobject->id == $id{
  1512.                 if (isset($this->_actionhandler[$i])) {
  1513.                     unset($this->_actionhandler[$i]);
  1514.                 }
  1515.                 
  1516.                 $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered'__FILE____LINE__);
  1517.                 $this->_reorderactionhandler();
  1518.                 return true;
  1519.             }
  1520.         }
  1521.         
  1522.         $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: could not find actionhandler id: '.$id.' _not_ unregistered'__FILE____LINE__);
  1523.         return false;
  1524.     }
  1525.     
  1526.     /**
  1527.      * registers a timehandler and returns the assigned id
  1528.      *
  1529.      * Registers a timehandler in Net_SmartIRC, which will be called in the specified interval.
  1530.      * The timehandler id is needed for unregistering the timehandler.
  1531.      *
  1532.      * @see example7.php
  1533.      * @param integer $interval interval time in milliseconds
  1534.      * @param object $object a reference to the objects of the method
  1535.      * @param string $methodname the methodname that will be called when the handler happens
  1536.      * @return integer assigned timehandler id
  1537.      * @access public
  1538.      */
  1539.     function registerTimehandler($interval&$object$methodname)
  1540.     {
  1541.         $id $this->_timehandlerid++;
  1542.         $newtimehandler &new Net_SmartIRC_timehandler();
  1543.         
  1544.         $newtimehandler->id = $id;
  1545.         $newtimehandler->interval = $interval;
  1546.         $newtimehandler->object = &$object;
  1547.         $newtimehandler->method = $methodname;
  1548.         $newtimehandler->lastmicrotimestamp = $this->_microint();
  1549.         
  1550.         $this->_timehandler[&$newtimehandler;
  1551.         $this->log(SMARTIRC_DEBUG_TIMEHANDLER'DEBUG_TIMEHANDLER: timehandler('.$id.') registered'__FILE____LINE__);
  1552.         
  1553.         if (($interval $this->_mintimer|| ($this->_mintimer == false)) {
  1554.             $this->_mintimer $interval;
  1555.         }
  1556.             
  1557.         return $id;
  1558.     }
  1559.     
  1560.     /**
  1561.      * unregisters an existing timehandler via the id
  1562.      *
  1563.      * @see example7.php
  1564.      * @param integer $id 
  1565.      * @return boolean 
  1566.      * @access public
  1567.      */
  1568.     function unregisterTimeid($id)
  1569.     {
  1570.         $handler &$this->_timehandler;
  1571.         $handlercount count($handler);
  1572.         for ($i = 0; $i $handlercount$i++{
  1573.             $handlerobject &$handler[$i];
  1574.             
  1575.             if ($handlerobject->id == $id{
  1576.                 if (isset($this->_timehandler[$i])) {
  1577.                     unset($this->_timehandler[$i]);
  1578.                 }
  1579.                 
  1580.                 $this->log(SMARTIRC_DEBUG_TIMEHANDLER'DEBUG_TIMEHANDLER: timehandler('.$id.') unregistered'__FILE____LINE__);
  1581.                 $this->_reordertimehandler();
  1582.                 $this->_updatemintimer();
  1583.                 return true;
  1584.             }
  1585.         }
  1586.         
  1587.         $this->log(SMARTIRC_DEBUG_TIMEHANDLER'DEBUG_TIMEHANDLER: could not find timehandler id: '.$id.' _not_ unregistered'__FILE____LINE__);
  1588.         return false;
  1589.     }
  1590.     
  1591.     function loadModule($name)
  1592.     {
  1593.         // is the module already loaded?
  1594.         if (in_array($name$this->_modules)) {
  1595.             $this->log(SMARTIRC_DEBUG_NOTICE'WARNING! module with the name "'.$name.'" already loaded!'__FILE____LINE__);
  1596.             return false;
  1597.         }
  1598.         
  1599.         $filename $this->_modulepath.'/'.$name.'.php';
  1600.         if (!file_exists($filename)) {
  1601.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: couldn\'t load module "'.$filename.'" file doesn\'t exist'__FILE____LINE__);
  1602.             return false;
  1603.         }
  1604.         
  1605.         $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: loading module: "'.$name.'"...'__FILE____LINE__);
  1606.         // pray that there is no parse error, it will kill us!
  1607.         include_once($filename);
  1608.         $classname 'Net_SmartIRC_module_'.$name;
  1609.         
  1610.         if (!class_exists($classname)) {
  1611.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: class '.$classname.' not found in '.$filename__FILE____LINE__);
  1612.             return false;
  1613.         }
  1614.         
  1615.         $methods get_class_methods($classname);
  1616.         if (!in_array('module_init'$methods)) {
  1617.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: required method'.$classname.'::module_init not found, aborting...'__FILE____LINE__);
  1618.             return false;
  1619.         }
  1620.         
  1621.         if (!in_array('module_exit'$methods)) {
  1622.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: required method'.$classname.'::module_exit not found, aborting...'__FILE____LINE__);
  1623.             return false;
  1624.         }
  1625.         
  1626.         $vars array_keys(get_class_vars($classname));
  1627.         if (!in_array('name'$vars)) {
  1628.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: required variable '.$classname.'::name not found, aborting...'__FILE____LINE__);
  1629.             return false;
  1630.         }
  1631.         
  1632.         if (!in_array('description'$vars)) {
  1633.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: required variable '.$classname.'::description not found, aborting...'__FILE____LINE__);
  1634.             return false;
  1635.         }
  1636.         
  1637.         if (!in_array('author'$vars)) {
  1638.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: required variable '.$classname.'::author not found, aborting...'__FILE____LINE__);
  1639.             return false;
  1640.         }
  1641.         
  1642.         if (!in_array('license'$vars)) {
  1643.             $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: required variable '.$classname.'::license not found, aborting...'__FILE____LINE__);
  1644.             return false;
  1645.         }
  1646.         
  1647.         // looks like the module satisfies us
  1648.         $module &new $classname;
  1649.         $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: successful created instance of: '.$classname__FILE____LINE__);
  1650.         
  1651.         $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: calling '.$classname.'::module_init()'__FILE____LINE__);
  1652.         $module->module_init($this);
  1653.         $this->_modules[$name&$module;
  1654.         
  1655.         $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: successful loaded module: '.$name__FILE____LINE__);
  1656.         return true;
  1657.     }
  1658.     
  1659.     function unloadModule($name)
  1660.     {
  1661.         $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: unloading module: '.$name.'...'__FILE____LINE__);
  1662.         
  1663.         $modules_keys array_keys($this->_modules);
  1664.         $modulecount count($modules_keys);
  1665.         for ($i = 0; $i $modulecount$i++{
  1666.             $module &$this->_modules[$modules_keys[$i]];
  1667.             $modulename strtolower(get_class($module));
  1668.             
  1669.             if ($modulename == 'net_smartirc_module_'.$name{
  1670.                 $module->module_exit($this);
  1671.                 unset($this->_modules[$i]);
  1672.                 $this->_reordermodules();
  1673.                 $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: successful unloaded module: '.$name__FILE____LINE__);
  1674.                 return true;
  1675.             }
  1676.         }
  1677.         
  1678.         $this->log(SMARTIRC_DEBUG_MODULES'DEBUG_MODULES: couldn\'t unloaded module: '.$name.' (it\'s not loaded!)'__FILE____LINE__);
  1679.         return false;
  1680.     }
  1681.     
  1682.     // <private methods>
  1683.     /**
  1684.      * changes a already used nickname to a new nickname plus 3 random digits
  1685.      *
  1686.      * @return void 
  1687.      * @access private
  1688.      */
  1689.     function _nicknameinuse()
  1690.     {
  1691.         $newnickname substr($this->_nick05).rand(0999);
  1692.         $this->changeNick($newnicknameSMARTIRC_CRITICAL);
  1693.     }
  1694.     
  1695.     /**
  1696.      * sends an IRC message
  1697.      *
  1698.      * Adds a message to the messagequeue, with the optional priority.
  1699.      * $priority:
  1700.      * SMARTIRC_CRITICAL
  1701.      * SMARTIRC_HIGH
  1702.      * SMARTIRC_MEDIUM
  1703.      * SMARTIRC_LOW
  1704.      *
  1705.      * @param string $data 
  1706.      * @param integer $priority must be one of the priority constants
  1707.      * @return boolean 
  1708.      * @access public
  1709.      */
  1710.     function send($data$priority = SMARTIRC_MEDIUM)
  1711.     {
  1712.         return $this->_send($data$priority);
  1713.     }
  1714.     
  1715.     /**
  1716.      * sends an IRC message
  1717.      *
  1718.      * Adds a message to the messagequeue, with the optional priority.
  1719.      * $priority:
  1720.      * SMARTIRC_CRITICAL
  1721.      * SMARTIRC_HIGH
  1722.      * SMARTIRC_MEDIUM
  1723.      * SMARTIRC_LOW
  1724.      *
  1725.      * @param string $data 
  1726.      * @param integer $priority must be one of the priority constants
  1727.      * @return boolean 
  1728.      * @access private
  1729.      */
  1730.     function _send($data$priority = SMARTIRC_MEDIUM)
  1731.     {
  1732.         switch ($priority{
  1733.             case SMARTIRC_CRITICAL:
  1734.                 $this->_rawsend($data);
  1735.             break;
  1736.             case SMARTIRC_HIGH:
  1737.             case SMARTIRC_MEDIUM:
  1738.             case SMARTIRC_LOW:
  1739.                 $this->_messagebuffer[$priority][$data;
  1740.             break;
  1741.             default:
  1742.                 $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: message ('.$data.') with an invalid priority passed ('.$priority.'), message is ignored!'__FILE____LINE__);
  1743.                 return false;
  1744.         }
  1745.         
  1746.         return true;
  1747.     }
  1748.     
  1749.     /**
  1750.      * checks the buffer if there are messages to send
  1751.      *
  1752.      * @return void 
  1753.      * @access private
  1754.      */
  1755.     function _checkbuffer()
  1756.     {
  1757.         if (!$this->_loggedin{
  1758.             return;
  1759.         }
  1760.         
  1761.         static $highsent = 0;
  1762.         static $lastmicrotimestamp = 0;
  1763.         
  1764.         if ($lastmicrotimestamp == 0{
  1765.             $lastmicrotimestamp $this->_microint();
  1766.         }
  1767.         
  1768.         $highcount = count($this->_messagebuffer[SMARTIRC_HIGH]);
  1769.         $mediumcount = count($this->_messagebuffer[SMARTIRC_MEDIUM]);
  1770.         $lowcount = count($this->_messagebuffer[SMARTIRC_LOW]);
  1771.         $this->_messagebuffersize = $highcount+$mediumcount+$lowcount;
  1772.         
  1773.         // don't send them too fast
  1774.         if ($this->_microint(>= ($lastmicrotimestamp+($this->_senddelay/1000))) {
  1775.             $result = null;
  1776.             if ($highcount > 0 && $highsent <= 2{
  1777.                 $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_HIGH]));
  1778.                 $lastmicrotimestamp $this->_microint();
  1779.                 $highsent++;
  1780.             else if ($mediumcount > 0{
  1781.                 $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_MEDIUM]));
  1782.                 $lastmicrotimestamp $this->_microint();
  1783.                 $highsent = 0;
  1784.             else if ($lowcount > 0{
  1785.                 $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_LOW]));
  1786.                 $lastmicrotimestamp $this->_microint();
  1787.             }
  1788.         }
  1789.     }
  1790.     
  1791.     /**
  1792.      * Checks the running timers and calls the registered timehandler,
  1793.      * when the interval is reached.
  1794.      *
  1795.      * @return void 
  1796.      * @access private
  1797.      */
  1798.     function _checktimer()
  1799.     {
  1800.         if (!$this->_loggedin{
  1801.             return;
  1802.         }
  1803.         
  1804.         // has to be count() because the array may change during the loop!
  1805.         for ($i = 0; $i count($this->_timehandler)$i++{
  1806.             $handlerobject &$this->_timehandler[$i];
  1807.             $microtimestamp $this->_microint();
  1808.             if ($microtimestamp >= ($handlerobject->lastmicrotimestamp+($handlerobject->interval/1000))) {
  1809.                 $methodobject &$handlerobject->object;
  1810.                 $method $handlerobject->method;
  1811.                 $handlerobject->lastmicrotimestamp = $microtimestamp;
  1812.                 
  1813.                 if (@method_exists($methodobject$method)) {
  1814.                     $this->log(SMARTIRC_DEBUG_TIMEHANDLER'DEBUG_TIMEHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"'__FILE____LINE__);
  1815.                     $methodobject->$method($this);
  1816.                 }
  1817.             }
  1818.         }
  1819.     }
  1820.     
  1821.     /**
  1822.      * Checks if a receive or transmit timeout occured and reconnects if configured
  1823.      *
  1824.      * @return void 
  1825.      * @access private
  1826.      */
  1827.     function _checktimeout()
  1828.     {
  1829.         if ($this->_autoreconnect == true{
  1830.             $timestamp time();
  1831.             if ($this->_lastrx < ($timestamp $this->_rxtimeout)) {
  1832.                 $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: receive timeout detected, doing reconnect...'__FILE____LINE__);
  1833.                 $this->_delayReconnect();
  1834.                 $this->reconnect();
  1835.             else if ($this->_lasttx < ($timestamp $this->_txtimeout)) {
  1836.                 $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: transmit timeout detected, doing reconnect...'__FILE____LINE__);
  1837.                 $this->_delayReconnect();
  1838.                 $this->reconnect();
  1839.             }
  1840.         }
  1841.     }
  1842.     
  1843.     /**
  1844.      * sends a raw message to the IRC server (don't use this!!)
  1845.      *
  1846.      * Use message() or send() instead.
  1847.      *
  1848.      * @param string $data 
  1849.      * @return boolean 
  1850.      * @access private
  1851.      */
  1852.     function _rawsend($data)
  1853.     {
  1854.         if ($this->_state(== SMARTIRC_STATE_CONNECTED{
  1855.             $this->log(SMARTIRC_DEBUG_IRCMESSAGES'DEBUG_IRCMESSAGES: sent: "'.$data.'"'__FILE____LINE__);
  1856.             
  1857.             if ($this->_usesockets == true{
  1858.                 $result = socket_write($this->_socket$data.SMARTIRC_CRLF);
  1859.             else {
  1860.                 $result fwrite($this->_socket$data.SMARTIRC_CRLF);
  1861.             }
  1862.             
  1863.             
  1864.             if ($result === false{
  1865.                 // writing to the socket failed, means the connection is broken
  1866.                 $this->_connectionerror = true;
  1867.                 
  1868.                 return false;
  1869.             else {
  1870.                 $this->_lasttx = time();
  1871.                 return true;
  1872.             }
  1873.         else {
  1874.             return false;
  1875.         }
  1876.     }
  1877.     
  1878.     /**
  1879.      * goes into main receive mode _once_ per call and waits for messages from the IRC server
  1880.      *
  1881.      * @return void 
  1882.      * @access private
  1883.      */
  1884.     function _rawreceive()
  1885.     {
  1886.         $lastpart '';
  1887.         $rawdataar = array();
  1888.         
  1889.         $this->_checkbuffer();
  1890.         
  1891.         $timeout $this->_selecttimeout();
  1892.         if ($this->_usesockets == true{
  1893.             $sread = array($this->_socket);
  1894.             $result = socket_select($sread$w = null$e = null0$timeout*1000);
  1895.             
  1896.             if ($result == 1{
  1897.                 // the socket got data to read
  1898.                 $rawdata = socket_read($this->_socket10240);
  1899.             else if ($result === false{
  1900.                 // panic! panic! something went wrong!
  1901.                 $this->log(SMARTIRC_DEBUG_NOTICE'WARNING: socket_select() returned false, something went wrong! Reason: '.socket_strerror(socket_last_error())__FILE____LINE__);
  1902.                 exit;
  1903.             else {
  1904.                 // no data
  1905.                 $rawdata = null;
  1906.             }
  1907.         else {
  1908.             usleep($this->_receivedelay*1000);
  1909.             $rawdata fread($this->_socket10240);
  1910.         }
  1911.         if ($rawdata === false{
  1912.             // reading from the socket failed, the connection is broken
  1913.             $this->_connectionerror = true;
  1914.         }
  1915.         
  1916.         $this->_checktimer();
  1917.         $this->_checktimeout();
  1918.         
  1919.         if ($rawdata !== null && !empty($rawdata)) {
  1920.             $this->_lastrx = time();
  1921.             $rawdata str_replace("\r"''$rawdata);
  1922.             $rawdata $lastpart.$rawdata;
  1923.             
  1924.             $lastpart substr($rawdatastrrpos($rawdata ,"\n")+1);
  1925.             $rawdata substr($rawdata0strrpos($rawdata ,"\n"));
  1926.             $rawdataar explode("\n"$rawdata);
  1927.         }
  1928.         
  1929.         // loop through our received messages
  1930.         while (count($rawdataar> 0{
  1931.             $rawline array_shift($rawdataar);
  1932.             $validmessage = false;
  1933.             
  1934.             $this->log(SMARTIRC_DEBUG_IRCMESSAGES'DEBUG_IRCMESSAGES: received: "'.$rawline.'"'__FILE____LINE__);
  1935.             
  1936.             // building our data packet
  1937.             $ircdata &new Net_SmartIRC_data();
  1938.             $ircdata->rawmessage = $rawline;
  1939.             $lineex explode(' '$rawline);
  1940.             $ircdata->rawmessageex = $lineex;
  1941.             $messagecode $lineex[0];
  1942.             
  1943.             if (substr($rawline01== ':'{
  1944.                 $validmessage = true;
  1945.                 $line substr($rawline1);
  1946.                 $lineex explode(' '$line);
  1947.                 
  1948.                 // conform to RFC 2812
  1949.                 $from $lineex[0];
  1950.                 $messagecode $lineex[1];
  1951.                 $exclamationpos strpos($from'!');
  1952.                 $atpos strpos($from'@');
  1953.                 $colonpos strpos($line' :');
  1954.                 if ($colonpos !== false{
  1955.                     // we want the exact position of ":" not beginning from the space
  1956.                     $colonpos += 1;
  1957.                 }
  1958.                 $ircdata->nick = substr($from0$exclamationpos);
  1959.                 $ircdata->ident = substr($from$exclamationpos+1($atpos-$exclamationpos)-1);
  1960.                 $ircdata->host = substr($from$atpos+1);
  1961.                 $ircdata->type = $this->_gettype($rawline);
  1962.                 $ircdata->from = $from;
  1963.                 if ($colonpos !== false{
  1964.                     $ircdata->message = substr($line$colonpos+1);
  1965.                     $ircdata->messageex = explode(' '$ircdata->message);
  1966.                 }
  1967.                 
  1968.                 if ($ircdata->type (SMARTIRC_TYPE_CHANNEL|
  1969.                                 SMARTIRC_TYPE_ACTION|
  1970.                                 SMARTIRC_TYPE_MODECHANGE|
  1971.                                 SMARTIRC_TYPE_TOPICCHANGE|
  1972.                                 SMARTIRC_TYPE_KICK|
  1973.                                 SMARTIRC_TYPE_PART|
  1974.                                 SMARTIRC_TYPE_JOIN)) {
  1975.                     $ircdata->channel = $lineex[2];
  1976.                 else if ($ircdata->type (SMARTIRC_TYPE_WHO|
  1977.                                     SMARTIRC_TYPE_BANLIST|
  1978.                                     SMARTIRC_TYPE_TOPIC|
  1979.                                     SMARTIRC_TYPE_CHANNELMODE)) {
  1980.                     $ircdata->channel = $lineex[3];
  1981.                 else if ($ircdata->type SMARTIRC_TYPE_NAME{
  1982.                     $ircdata->channel = $lineex[4];
  1983.                 }
  1984.                 
  1985.                 if ($ircdata->channel !== null{
  1986.                     if (substr($ircdata->channel01== ':'{
  1987.                         $ircdata->channel = substr($ircdata->channel1);
  1988.                     }
  1989.                 }
  1990.                 
  1991.                 $this->log(SMARTIRC_DEBUG_MESSAGEPARSER'DEBUG_MESSAGEPARSER: ircdata nick: "'.$ircdata->nick.
  1992.                                                             '" ident: "'.$ircdata->ident.
  1993.                                                             '" host: "'.$ircdata->host.
  1994.                                                             '" type: "'.$ircdata->type.
  1995.                                                             '" from: "'.$ircdata->from.
  1996.                                                             '" channel: "'.$ircdata->channel.
  1997.                                                             '" message: "'.$ircdata->message.
  1998.                                                             '"'__FILE____LINE__);
  1999.             }
  2000.             
  2001.             // lets see if we have a messagehandler for it
  2002.             $this->_handlemessage($messagecode$ircdata);
  2003.             
  2004.             if ($validmessage == true{
  2005.                 // now the actionhandlers are comming
  2006.                 $this->_handleactionhandler($ircdata);
  2007.             }
  2008.             
  2009.             if (isset($ircdata)) {
  2010.                 unset($ircdata);
  2011.             }
  2012.         }
  2013.     }
  2014.     
  2015.     /**
  2016.      * sends the pong for keeping alive
  2017.      *
  2018.      * Sends the PONG signal as reply of the PING from the IRC server.
  2019.      *
  2020.      * @param string $data 
  2021.      * @return void 
  2022.      * @access private
  2023.      */
  2024.     function _pong($data)
  2025.     {
  2026.         $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: Ping? Pong!'__FILE____LINE__);
  2027.         $this->_send('PONG '.$dataSMARTIRC_CRITICAL);
  2028.     }
  2029.     
  2030.     /**
  2031.      * returns the calculated selecttimeout value
  2032.      *
  2033.      * @return integer selecttimeout in microseconds
  2034.      * @access private
  2035.      */
  2036.     function _selecttimeout()
  2037.     {
  2038.         if ($this->_messagebuffersize == 0{
  2039.             $this->_selecttimeout = null;
  2040.             
  2041.             if ($this->_mintimer != false{
  2042.                 $this->_calculateselecttimeout($this->_mintimer);
  2043.             }
  2044.             
  2045.             if ($this->_autoreconnect == true{
  2046.                 $this->_calculateselecttimeout($this->_rxtimeout*1000);
  2047.             }
  2048.             
  2049.             $this->_calculateselecttimeout($this->_maxtimer);
  2050.             return $this->_selecttimeout;
  2051.         else {
  2052.             return $this->_senddelay;
  2053.         }
  2054.     }
  2055.     
  2056.     /**
  2057.      * calculates the selecttimeout value
  2058.      *
  2059.      * @return void 
  2060.      * @access private
  2061.      */
  2062.     function _calculateselecttimeout($microseconds)
  2063.     {
  2064.         if (($this->_selecttimeout > $microseconds|| $this->_selecttimeout === null{
  2065.             $this->_selecttimeout = $microseconds;
  2066.         }
  2067.     }
  2068.     
  2069.     /**
  2070.      * updates _mintimer to the smallest timer interval
  2071.      *
  2072.      * @return void 
  2073.      * @access private
  2074.      */
  2075.     function _updatemintimer()
  2076.     {
  2077.         $timerarray = array();
  2078.         foreach ($this->_timehandler as $values{
  2079.             $timerarray[$values->interval;
  2080.         }
  2081.         
  2082.         $result array_multisort($timerarraySORT_NUMERICSORT_ASC);
  2083.         if ($result == true && isset($timerarray[0])) {
  2084.             $this->_mintimer = $timerarray[0];
  2085.         else {
  2086.             $this->_mintimer = false;
  2087.         }
  2088.     }
  2089.     
  2090.     /**
  2091.      * reorders the actionhandler array, needed after removing one
  2092.      *
  2093.      * @return void 
  2094.      * @access private
  2095.      */
  2096.     function _reorderactionhandler()
  2097.     {
  2098.         $orderedactionhandler = array();
  2099.         foreach ($this->_actionhandler as $value{
  2100.             $orderedactionhandler[$value;
  2101.         }
  2102.         $this->_actionhandler = &$orderedactionhandler;
  2103.     }
  2104.     
  2105.     /**
  2106.      * reorders the timehandler array, needed after removing one
  2107.      *
  2108.      * @return void 
  2109.      * @access private
  2110.      */
  2111.     function _reordertimehandler()
  2112.     {
  2113.         $orderedtimehandler = array();
  2114.         foreach ($this->_timehandler as $value{
  2115.             $orderedtimehandler[$value;
  2116.         }
  2117.         $this->_timehandler = &$orderedtimehandler;
  2118.     }
  2119.     
  2120.     /**
  2121.      * reorders the modules array, needed after removing one
  2122.      *
  2123.      * @return void 
  2124.      * @access private
  2125.      */
  2126.     function _reordermodules()
  2127.     {
  2128.         $orderedmodules = array();
  2129.         foreach ($this->_modules as $value{
  2130.             $orderedmodules[$value;
  2131.         }
  2132.         $this->_modules = &$orderedmodules;
  2133.     }
  2134.  
  2135.     /**
  2136.      * determines the messagetype of $line
  2137.      *
  2138.      * Analyses the type of an IRC message and returns the type.
  2139.      *
  2140.      * @param string $line 
  2141.      * @return integer SMARTIRC_TYPE_* constant
  2142.      * @access private
  2143.      */
  2144.     function _gettype($line)
  2145.     {
  2146.         if (preg_match('/^:[^ ]+? [0-9]{3} .+$/'$line== 1{
  2147.             $lineex explode(' '$line);
  2148.             $code $lineex[1];
  2149.                 
  2150.             switch ($code{
  2151.                 case SMARTIRC_RPL_WELCOME:
  2152.                 case SMARTIRC_RPL_YOURHOST:
  2153.                 case SMARTIRC_RPL_CREATED:
  2154.                 case SMARTIRC_RPL_MYINFO:
  2155.                 case SMARTIRC_RPL_BOUNCE:
  2156.                     return SMARTIRC_TYPE_LOGIN;
  2157.                 case SMARTIRC_RPL_LUSERCLIENT:
  2158.                 case SMARTIRC_RPL_LUSEROP:
  2159.                 case SMARTIRC_RPL_LUSERUNKNOWN:
  2160.                 case SMARTIRC_RPL_LUSERME:
  2161.                 case SMARTIRC_RPL_LUSERCHANNELS:
  2162.                     return SMARTIRC_TYPE_INFO;
  2163.                 case SMARTIRC_RPL_MOTDSTART:
  2164.                 case SMARTIRC_RPL_MOTD:
  2165.                 case SMARTIRC_RPL_ENDOFMOTD:
  2166.                     return SMARTIRC_TYPE_MOTD;
  2167.                 case SMARTIRC_RPL_NAMREPLY:
  2168.                 case SMARTIRC_RPL_ENDOFNAMES:
  2169.                     return SMARTIRC_TYPE_NAME;
  2170.                 case SMARTIRC_RPL_WHOREPLY:
  2171.                 case SMARTIRC_RPL_ENDOFWHO:
  2172.                     return SMARTIRC_TYPE_WHO;
  2173.                 case SMARTIRC_RPL_LISTSTART:
  2174.                     return SMARTIRC_TYPE_NONRELEVANT;
  2175.                 case SMARTIRC_RPL_LIST:
  2176.                 case SMARTIRC_RPL_LISTEND:
  2177.                     return SMARTIRC_TYPE_LIST;
  2178.                 case SMARTIRC_RPL_BANLIST:
  2179.                 case SMARTIRC_RPL_ENDOFBANLIST:
  2180.                     return SMARTIRC_TYPE_BANLIST;
  2181.                 case SMARTIRC_RPL_TOPIC:
  2182.                     return SMARTIRC_TYPE_TOPIC;
  2183.                 case SMARTIRC_RPL_WHOISUSER:
  2184.                 case SMARTIRC_RPL_WHOISSERVER:
  2185.                 case SMARTIRC_RPL_WHOISOPERATOR:
  2186.                 case SMARTIRC_RPL_WHOISIDLE:
  2187.                 case SMARTIRC_RPL_ENDOFWHOIS:
  2188.                 case SMARTIRC_RPL_WHOISCHANNELS:
  2189.                     return SMARTIRC_TYPE_WHOIS;
  2190.                 case SMARTIRC_RPL_WHOWASUSER:
  2191.                 case SMARTIRC_RPL_ENDOFWHOWAS:
  2192.                     return SMARTIRC_TYPE_WHOWAS;
  2193.                 case SMARTIRC_RPL_UMODEIS:
  2194.                     return SMARTIRC_TYPE_USERMODE;
  2195.                 case SMARTIRC_RPL_CHANNELMODEIS:
  2196.                     return SMARTIRC_TYPE_CHANNELMODE;
  2197.                 case SMARTIRC_ERR_NICKNAMEINUSE:
  2198.                 case SMARTIRC_ERR_NOTREGISTERED:
  2199.                     return SMARTIRC_TYPE_ERROR;
  2200.                 default:
  2201.                     $this->log(SMARTIRC_DEBUG_IRCMESSAGES'DEBUG_IRCMESSAGES: replycode UNKNOWN ('.$code.'): "'.$line.'"'__FILE____LINE__);
  2202.             }
  2203.         }
  2204.         
  2205.         if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'ACTION .*'.chr(1).'$/'$line== 1{
  2206.             return SMARTIRC_TYPE_ACTION;
  2207.         else if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'.*'.chr(1).'$/'$line== 1{
  2208.             return (SMARTIRC_TYPE_CTCP_REQUEST|SMARTIRC_TYPE_CTCP);
  2209.         else if (preg_match('/^:.*? NOTICE .* :'.chr(1).'.*'.chr(1).'$/'$line== 1{
  2210.             return (SMARTIRC_TYPE_CTCP_REPLY|SMARTIRC_TYPE_CTCP);
  2211.         else if (preg_match('/^:.*? PRIVMSG (\&|\#|\+|\!).* :.*$/'$line== 1{
  2212.             return SMARTIRC_TYPE_CHANNEL;
  2213.         else if (preg_match('/^:.*? PRIVMSG .*:.*$/'$line== 1{
  2214.             return SMARTIRC_TYPE_QUERY;
  2215.         else if (preg_match('/^:.*? NOTICE .* :.*$/'$line== 1{
  2216.             return SMARTIRC_TYPE_NOTICE;
  2217.         else if (preg_match('/^:.*? INVITE .* .*$/'$line== 1{
  2218.             return SMARTIRC_TYPE_INVITE;
  2219.         else if (preg_match('/^:.*? JOIN .*$/'$line== 1{
  2220.             return SMARTIRC_TYPE_JOIN;
  2221.         else if (preg_match('/^:.*? TOPIC .* :.*$/'$line== 1{
  2222.             return SMARTIRC_TYPE_TOPICCHANGE;
  2223.         else if (preg_match('/^:.*? NICK .*$/'$line== 1{
  2224.             return SMARTIRC_TYPE_NICKCHANGE;
  2225.         else if (preg_match('/^:.*? KICK .* .*$/'$line== 1{
  2226.             return SMARTIRC_TYPE_KICK;
  2227.         else if (preg_match('/^:.*? PART .*$/'$line== 1{
  2228.             return SMARTIRC_TYPE_PART;
  2229.         else if (preg_match('/^:.*? MODE .* .*$/'$line== 1{
  2230.             return SMARTIRC_TYPE_MODECHANGE;
  2231.         else if (preg_match('/^:.*? QUIT :.*$/'$line== 1{
  2232.             return SMARTIRC_TYPE_QUIT;
  2233.         else {
  2234.             $this->log(SMARTIRC_DEBUG_MESSAGETYPES'DEBUG_MESSAGETYPES: SMARTIRC_TYPE_UNKNOWN!: "'.$line.'"'__FILE____LINE__);
  2235.             return SMARTIRC_TYPE_UNKNOWN;
  2236.         }
  2237.     }
  2238.     
  2239.     /**
  2240.      * updates the current connection state
  2241.      *
  2242.      * @return boolean 
  2243.      * @access private
  2244.      */
  2245.     function _updatestate()
  2246.     {
  2247.         if (is_resource($this->_socket)) {
  2248.             $rtype get_resource_type($this->_socket);
  2249.             if (($this->_socket !== false&& 
  2250.                 ($rtype == 'socket' || $rtype == 'Socket' || $rtype == 'stream')) {
  2251.                 $this->_state = true;
  2252.                 return true;
  2253.             }
  2254.         else {
  2255.             $this->_state = false;
  2256.             $this->_loggedin = false;
  2257.             return false;
  2258.         }
  2259.     }
  2260.     
  2261.     /**
  2262.      * returns the current connection state
  2263.      *
  2264.      * @return integer SMARTIRC_STATE_CONNECTED or SMARTIRC_STATE_DISCONNECTED
  2265.      * @access private
  2266.      */
  2267.     function _state()
  2268.     {
  2269.         $result $this->_updatestate();
  2270.         
  2271.         if ($result == true{
  2272.             return SMARTIRC_STATE_CONNECTED;
  2273.         else {
  2274.             return SMARTIRC_STATE_DISCONNECTED;
  2275.         }
  2276.     }
  2277.     
  2278.     /**
  2279.      * tries to find a messagehandler for the received message ($ircdata) and calls it
  2280.      *
  2281.      * @param string $messagecode 
  2282.      * @param object $ircdata 
  2283.      * @return void 
  2284.      * @access private
  2285.      */
  2286.     function _handlemessage($messagecode&$ircdata)
  2287.     {
  2288.         $found = false;
  2289.         
  2290.         if (is_numeric($messagecode)) {
  2291.             if (!array_key_exists($messagecode$this->nreplycodes)) {
  2292.                 $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER'DEBUG_MESSAGEHANDLER: ignoring unrecognized messagecode! "'.$messagecode.'"'__FILE____LINE__);
  2293.                 $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER'DEBUG_MESSAGEHANDLER: this IRC server ('.$this->_address.') doesn\'t conform to the RFC 2812!'__FILE____LINE__);
  2294.                 return;
  2295.             }
  2296.             
  2297.             $methodname 'event_'.strtolower($this->nreplycodes[$messagecode]);
  2298.             $_methodname '_'.$methodname;
  2299.             $_codetype 'by numeric';
  2300.         else if (is_string($messagecode)) // its not numericcode so already a name/string
  2301.             $methodname 'event_'.strtolower($messagecode);
  2302.             $_methodname '_'.$methodname;
  2303.             $_codetype 'by string';
  2304.         }
  2305.         
  2306.         // if exists call internal method for the handling
  2307.         if (@method_exists($this$_methodname)) {
  2308.            $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER'DEBUG_MESSAGEHANDLER: calling internal method "'.get_class($this).'->'.$_methodname.'" ('.$_codetype.')'__FILE____LINE__);
  2309.            $this->$_methodname($ircdata);
  2310.            $found = true;
  2311.         }
  2312.         
  2313.         // if exist, call user defined method for the handling
  2314.         if (@method_exists($this$methodname)) {
  2315.            $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER'DEBUG_MESSAGEHANDLER: calling user defined method "'.get_class($this).'->'.$methodname.'" ('.$_codetype.')'__FILE____LINE__);
  2316.            $this->$methodname($ircdata);
  2317.            $found = true;
  2318.         }
  2319.         
  2320.         if ($found == false{
  2321.             $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER'DEBUG_MESSAGEHANDLER: no method found for "'.$messagecode.'" ('.$methodname.')'__FILE____LINE__);
  2322.         }
  2323.     }
  2324.     
  2325.     /**
  2326.      * tries to find a actionhandler for the received message ($ircdata) and calls it
  2327.      *
  2328.      * @param object $ircdata 
  2329.      * @return void 
  2330.      * @access private
  2331.      */
  2332.     function _handleactionhandler(&$ircdata)
  2333.     {
  2334.         $handler &$this->_actionhandler;
  2335.         $handlercount count($handler);
  2336.         for ($i = 0; $i $handlercount$i++{
  2337.             $handlerobject &$handler[$i];
  2338.             
  2339.             if (substr($handlerobject->message01== '/'{
  2340.                 $regex $handlerobject->message;
  2341.             else {
  2342.                 $regex '/'.$handlerobject->message.'/';
  2343.             }
  2344.             
  2345.             if (($handlerobject->type $ircdata->type&&
  2346.                 (preg_match($regex$ircdata->message== 1)) {
  2347.                 
  2348.                 $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: actionhandler match found for id: '.$i.' type: '.$ircdata->type.' message: "'.$ircdata->message.'" regex: "'.$regex.'"'__FILE____LINE__);
  2349.                 
  2350.                 $methodobject &$handlerobject->object;
  2351.                 $method $handlerobject->method;
  2352.                 
  2353.                 if (@method_exists($methodobject$method)) {
  2354.                     $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"'__FILE____LINE__);
  2355.                     $methodobject->$method($this$ircdata);
  2356.                 else {
  2357.                     $this->log(SMARTIRC_DEBUG_ACTIONHANDLER'DEBUG_ACTIONHANDLER: method doesn\'t exist! "'.get_class($methodobject).'->'.$method.'"'__FILE____LINE__);
  2358.                 }
  2359.             }
  2360.         }
  2361.     }
  2362.  
  2363.     /**
  2364.      * Delay reconnect
  2365.      *
  2366.      * @return void 
  2367.      * @access private
  2368.      */
  2369.     function _delayReconnect()
  2370.     {
  2371.         if ($this->_reconnectdelay > 0{
  2372.             $this->log(SMARTIRC_DEBUG_CONNECTION'DEBUG_CONNECTION: delaying reconnect for '.$this->_reconnectdelay.' ms'__FILE____LINE__);
  2373.             usleep($this->_reconnectdelay * 1000);
  2374.         }
  2375.     }
  2376.     
  2377.     /**
  2378.      * getting current microtime, needed for benchmarks
  2379.      *
  2380.      * @return float 
  2381.      * @access private
  2382.      */
  2383.     function _microint()
  2384.     {
  2385.         $tmp microtime();
  2386.         $parts explode(' '$tmp);
  2387.         $floattime = (float)$parts[0+ (float)$parts[1];
  2388.         return $floattime;
  2389.     }
  2390.     
  2391.     /**
  2392.      * adds an user to the channelobject or updates his info
  2393.      *
  2394.      * @param object $channel 
  2395.      * @param object $newuser 
  2396.      * @return void 
  2397.      * @access private
  2398.      */
  2399.     function _adduser(&$channel&$newuser)
  2400.     {
  2401.         $lowerednick strtolower($newuser->nick);
  2402.         if ($this->isJoined($channel->name$newuser->nick)) {
  2403.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: updating user: '.$newuser->nick.' on channel: '.$channel->name__FILE____LINE__);
  2404.             
  2405.             // lets update the existing user
  2406.             $currentuser &$channel->users[$lowerednick];
  2407.             
  2408.             if ($newuser->ident !== null{
  2409.                 $currentuser->ident = $newuser->ident;
  2410.             }
  2411.             if ($newuser->host !== null{
  2412.                 $currentuser->host = $newuser->host;
  2413.             }
  2414.             if ($newuser->realname !== null{
  2415.                 $currentuser->realname = $newuser->realname;
  2416.             }
  2417.             if ($newuser->op !== null{
  2418.                 $currentuser->op = $newuser->op;
  2419.             }
  2420.             if ($newuser->voice !== null{
  2421.                 $currentuser->voice = $newuser->voice;
  2422.             }
  2423.             if ($newuser->ircop !== null{
  2424.                 $currentuser->ircop = $newuser->ircop;
  2425.             }
  2426.             if ($newuser->away !== null{
  2427.                 $currentuser->away = $newuser->away;
  2428.             }
  2429.             if ($newuser->server !== null{
  2430.                 $currentuser->server = $newuser->server;
  2431.             }
  2432.             if ($newuser->hopcount !== null{
  2433.                 $currentuser->hopcount = $newuser->hopcount;
  2434.             }
  2435.         else {
  2436.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: adding user: '.$newuser->nick.' to channel: '.$channel->name__FILE____LINE__);
  2437.             
  2438.             // he is new just add the reference to him
  2439.             $channel->users[$lowerednick&$newuser;
  2440.         }
  2441.         
  2442.         $user &$channel->users[$lowerednick];
  2443.         if ($user->op{
  2444.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: adding op: '.$user->nick.' to channel: '.$channel->name__FILE____LINE__);
  2445.             $channel->ops[$user->nick= true;
  2446.         }
  2447.         if ($user->voice{
  2448.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING'DEBUG_CHANNELSYNCING: adding voice: '.$user