home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / SmartIRC.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  75.1 KB  |  2,521 lines

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