From 03af469738eb8b1e40c50619bec31c87a7df5fb6 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Wed, 2 Apr 2014 23:05:06 +0200 Subject: [PATCH] Many changes related to new irc scraping. --- bin/monitor.php | 2 +- lib/IRCScraper.php | 18 +- lib/Net_SmartIRC/Net/SmartIRC.php | 6181 ++++++++--------- lib/Net_SmartIRC/Net/SmartIRC/irccommands.php | 6 +- .../Net/SmartIRC/messagehandler.php | 3 +- lib/prehash.php | 1069 +-- 6 files changed, 3744 insertions(+), 3535 deletions(-) diff --git a/bin/monitor.php b/bin/monitor.php index abaf95d3a..5d7d4bc17 100644 --- a/bin/monitor.php +++ b/bin/monitor.php @@ -9,7 +9,7 @@ require_once(dirname(__FILE__)."/../lib/showsleep.php"); require_once(dirname(__FILE__)."/../lib/functions.php"); -$version="0.3r1052"; +$version="0.3r1053"; $db = new DB(); $functions = new Functions(); diff --git a/lib/IRCScraper.php b/lib/IRCScraper.php index 149b14161..7ca0b75ce 100644 --- a/lib/IRCScraper.php +++ b/lib/IRCScraper.php @@ -128,7 +128,7 @@ class IRCScraper */ public function __destruct() { - // Disconnect from IRC cleanly. + // Close the socket. if (!is_null($this->IRC)) { if (!$this->silent) { echo @@ -137,7 +137,7 @@ class IRCScraper '.' . PHP_EOL; } - $this->IRC->disconnect(); + $this->IRC->disconnect(true); } } @@ -278,7 +278,7 @@ class IRCScraper } // Login to IRC. - $this->IRC->login( + if (!$this->IRC->login( // Nick name. $nickname, // Real name. @@ -289,10 +289,18 @@ class IRCScraper $username, // Password. (empty($password) ? null : $password) - ); + )) { + exit('Error logging in to: (' . + $server . ':' . $port . ') nickname: (' . $nickname . + '). Verify your connection information, you might also be banned from this server or there might have been a connection issue.' . + PHP_EOL + ); + } // Join channels. - $this->IRC->join($channelList); + if (!$this->IRC->joinChannels($channelList)) { + exit('Error joining channels on (' . $server . ':' . $port . ') might be an issue with the server.' . PHP_EOL); + } if (!$this->silent) { echo diff --git a/lib/Net_SmartIRC/Net/SmartIRC.php b/lib/Net_SmartIRC/Net/SmartIRC.php index 5f5c4e3a0..668295575 100644 --- a/lib/Net_SmartIRC/Net/SmartIRC.php +++ b/lib/Net_SmartIRC/Net/SmartIRC.php @@ -58,2839 +58,2805 @@ define('SMARTIRC_VERSIONSTRING', 'Net_SmartIRC '.SMARTIRC_VERSION); */ class Net_SmartIRC_base { - /** - * @var resource - * @access private - */ - var $_socket; - - /** - * @var string - * @access private - */ - var $_address; - - /** - * @var integer - * @access private - */ - var $_port; - - /** - * @var string - * @access private - */ - var $_bindaddress = null; - - /** - * @var integer - * @access private - */ - var $_bindport = 0; - - /** - * @var string - * @access private - */ - var $_nick; - - /** - * @var string - * @access private - */ - var $_username; - - /** - * @var string - * @access private - */ - var $_realname; - - /** - * @var string - * @access private - */ - var $_usermode; - - /** - * @var string - * @access private - */ - var $_password; - - /** - * @var array - * @access private - */ - var $_performs = array(); - - /** - * @var boolean - * @access private - */ - var $_state = false; - - /** - * @var array - * @access private - */ - var $_actionhandler = array(); - - /** - * @var array - * @access private - */ - var $_timehandler = array(); - - /** - * @var integer - * @access private - */ - var $_debug = SMARTIRC_DEBUG_NOTICE; - - /** - * @var array - * @access private - */ - var $_messagebuffer = array(); - - /** - * @var integer - * @access private - */ - var $_messagebuffersize; - - /** - * @var boolean - * @access private - */ - var $_usesockets = false; - - /** - * @var integer - * @access private - */ - var $_receivedelay = 100; - - /** - * @var integer - * @access private - */ - var $_senddelay = 250; - - /** - * @var integer - * @access private - */ - var $_logdestination = SMARTIRC_STDOUT; - - /** - * @var resource - * @access private - */ - var $_logfilefp = 0; - - /** - * @var string - * @access private - */ - var $_logfile = 'Net_SmartIRC.log'; - - /** - * @var integer - * @access private - */ - var $_disconnecttime = 1000; - - /** - * @var boolean - * @access private - */ - var $_loggedin = false; - - /** - * @var boolean - * @access private - */ - var $_benchmark = false; - - /** - * @var integer - * @access private - */ - var $_benchmark_starttime; - - /** - * @var integer - * @access private - */ - var $_benchmark_stoptime; - - /** - * @var integer - * @access private - */ - var $_actionhandlerid = 0; - - /** - * @var integer - * @access private - */ - var $_timehandlerid = 0; - - /** - * @var array - * @access private - */ - var $_motd = array(); - - /** - * @var array - * @access private - */ - var $_channels = array(); - - /** - * @var boolean - * @access private - */ - var $_channelsyncing = false; - - /** - * @var array - * @access private - */ - var $_users = array(); - - /** - * @var boolean - * @access private - */ - var $_usersyncing = false; - - /** - * Stores the path to the modules that can be loaded. - * - * @var string - * @access private - */ - var $_modulepath = ''; - - /** - * Stores all objects of the modules. - * - * @var string - * @access private - */ - var $_modules = array(); - - /** - * @var string - * @access private - */ - var $_ctcpversion; - - /** - * @var mixed - * @access private - */ - var $_mintimer = false; - - /** - * @var integer - * @access private - */ - var $_maxtimer = 300000; - - /** - * @var integer - * @access private - */ - var $_txtimeout = 300; - - /** - * @var integer - * @access private - */ - var $_rxtimeout = 300; - - /** - * @var integer - * @access private - */ - var $_selecttimeout; - - /** - * @var integer - * @access private - */ - var $_lastrx; - - /** - * @var integer - * @access private - */ - var $_lasttx; - - /** - * @var boolean - * @access private - */ - var $_autoreconnect = false; - - /** - * @var integer - * @access private - */ - var $_reconnectdelay = 10000; - - /** - * @var boolean - * @access private - */ - var $_autoretry = false; - - /** - * @var integer - * @access private - */ - var $_autoretrymax = 5; - - /** - * @var integer - * @access private - */ - var $_autoretrycount = 0; - - /** - * @var boolean - * @access private - */ - var $_connectionerror = false; - - /** - * @var boolean - * @access private - */ - var $_runasdaemon = false; - - - /** - * All IRC replycodes, the index is the replycode name. - * - * @see $SMARTIRC_replycodes - * @var array - * @access public - */ - var $replycodes; - - /** - * All numeric IRC replycodes, the index is the numeric replycode. - * - * @see $SMARTIRC_nreplycodes - * @var array - * @access public - */ - var $nreplycodes; - - /** - * Stores all channels in this array where we are joined, works only if channelsyncing is activated. - * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc) - * $irc->channel['#test']->users['meebey']->nick; - * - * @see setChannelSyncing() - * @see Net_SmartIRC_channel - * @see Net_SmartIRC_channeluser - * @var array - * @access public - */ - var $channel; - - /** - * Stores all users that had/have contact with us (channel/query/notice etc.), works only if usersyncing is activated. - * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc) - * $irc->user['meebey']->host; - * - * @see setUserSyncing() - * @see Net_SmartIRC_ircuser - * @var array - * @access public - */ - var $user; - - /** - * Constructor. Initiates the messagebuffer and "links" the replycodes from - * global into properties. Also some PHP runtime settings are configured. - * - * @access public - */ - function __construct() - { - // precheck - $this->_checkPHPVersion(); - - ob_implicit_flush(true); - @set_time_limit(0); - $this->_messagebuffer[SMARTIRC_CRITICAL] = array(); - $this->_messagebuffer[SMARTIRC_HIGH] = array(); - $this->_messagebuffer[SMARTIRC_MEDIUM] = array(); - $this->_messagebuffer[SMARTIRC_LOW] = array(); - - $this->replycodes = &$GLOBALS['SMARTIRC_replycodes']; - $this->nreplycodes = &$GLOBALS['SMARTIRC_nreplycodes']; - - // hack till PHP allows (PHP5) $object->somemethod($param)->memberofobject - $this->channel = &$this->_channels; - // another hack - $this->user = &$this->_users; - - if (isset($_SERVER['REQUEST_METHOD'])) { - // the script is called from a browser, lets set default log destination - // to SMARTIRC_BROWSEROUT (makes browser friendly output) - $this->setLogdestination(SMARTIRC_BROWSEROUT); - } - } - - /** - * Enables/disables the usage of real sockets. - * - * Enables/disables the usage of real sockets instead of fsocks - * (works only if your PHP build has loaded the PHP socket extension) - * Default: false - * - * @param bool $boolean - * @return void - * @access public - */ - function setUseSockets($boolean) - { - if ($boolean === true) { - if (@extension_loaded('sockets')) { - $this->_usesockets = true; - } else { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket extension not loaded, trying to load it...', __FILE__, __LINE__); - - if (strtoupper(substr(PHP_OS, 0,3) == 'WIN')) { - $load_status = @dl('php_sockets.dll'); - } else { - $load_status = @dl('sockets.so'); - } - - if ($load_status) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket extension succesfully loaded', __FILE__, __LINE__); - $this->_usesockets = true; - } else { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: couldn\'t load the socket extension', __FILE__, __LINE__); - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: your PHP build doesn\'t support real sockets, will use fsocks instead', __FILE__, __LINE__); - $this->_usesockets = false; - } - } - } else { - $this->_usesockets = false; - } - } - - /** - * Sets an IP address (and optionally, a port) to bind the socket to. - * - * Limits the bot to claiming only one of the machine's IPs as its home. - * Only works with setUseSockets(TRUE). Call with no parameters to unbind. - * - * @param string $addr - * @return bool - * @access public - */ - function setBindAddress($addr=null,$port=0) - { - if ($this->_usesockets) { - $this->bindaddress = $addr; - $this->bindport = $port; - } - return $this->_usesockets; - } - - /** - * Sets the level of debug messages. - * - * Sets the debug level (bitwise), useful for testing/developing your code. - * Here the list of all possible debug levels: - * SMARTIRC_DEBUG_NONE - * SMARTIRC_DEBUG_NOTICE - * SMARTIRC_DEBUG_CONNECTION - * SMARTIRC_DEBUG_SOCKET - * SMARTIRC_DEBUG_IRCMESSAGES - * SMARTIRC_DEBUG_MESSAGETYPES - * SMARTIRC_DEBUG_ACTIONHANDLER - * SMARTIRC_DEBUG_TIMEHANDLER - * SMARTIRC_DEBUG_MESSAGEHANDLER - * SMARTIRC_DEBUG_CHANNELSYNCING - * SMARTIRC_DEBUG_MODULES - * SMARTIRC_DEBUG_USERSYNCING - * SMARTIRC_DEBUG_ALL - * - * Default: SMARTIRC_DEBUG_NOTICE - * - * @see DOCUMENTATION - * @see SMARTIRC_DEBUG_NOTICE - * @param integer $level - * @return void - * @access public - */ - function setDebug($level) - { - $this->_debug = $level; - } - - /** - * Enables/disables the benchmark engine. - * - * @param boolean $boolean - * @return void - * @access public - */ - function setBenchmark($boolean) - { - if (is_bool($boolean)) { - $this->_benchmark = $boolean; - } else { - $this->_benchmark = false; - } - } - - /** - * Deprecated, use setChannelSyncing() instead! - * - * @deprecated - * @param boolean $boolean - * @return void - * @access public - */ - function setChannelSynching($boolean) - { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: you are using setChannelSynching() which is a deprecated method, use setChannelSyncing() instead!', __FILE__, __LINE__); - $this->setChannelSyncing($boolean); - } - - /** - * Enables/disables channel syncing. - * - * Channel syncing means, all users on all channel we are joined are tracked in the - * channel array. This makes it very handy for botcoding. - * - * @param boolean $boolean - * @return void - * @access public - */ - function setChannelSyncing($boolean) - { - if (is_bool($boolean)) { - $this->_channelsyncing = $boolean; - } else { - $this->_channelsyncing = false; - } - - if ($this->_channelsyncing == true) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: Channel syncing enabled', __FILE__, __LINE__); - } else { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: Channel syncing disabled', __FILE__, __LINE__); - } - } - - /** - * Enables/disables user syncing. - * - * User syncing means, all users we have or had contact with through channel, query or - * notice are tracked in the $irc->user array. This is very handy for botcoding. - * - * @param boolean $boolean - * @return void - * @access public - */ - function setUserSyncing($boolean) - { - if (is_bool($boolean)) { - $this->_usersyncing = $boolean; - } else { - $this->_usersyncing = false; - } - - if ($this->_usersyncing == true) { - $this->log(SMARTIRC_DEBUG_USERSYNCING, 'DEBUG_USERSYNCING: User syncing enabled', __FILE__, __LINE__); - } else { - $this->log(SMARTIRC_DEBUG_USERSYNCING, 'DEBUG_USERSYNCING: User syncing disabled', __FILE__, __LINE__); - } - } - - /** - * Sets the CTCP version reply string. - * - * @param string $versionstring - * @return void - * @access public - */ - function setCtcpVersion($versionstring) - { - $this->_ctcpversion = $versionstring; - } - - /** - * Sets the destination of all log messages. - * - * Sets the destination of log messages. - * $type can be: - * SMARTIRC_FILE for saving the log into a file - * SMARTIRC_STDOUT for echoing the log to stdout - * SMARTIRC_SYSLOG for sending the log to the syslog - * Default: SMARTIRC_STDOUT - * - * @see SMARTIRC_STDOUT - * @param integer $type must be on of the constants - * @return void - * @access public - */ - function setLogdestination($type) - { - switch ($type) { - case SMARTIRC_FILE: - case SMARTIRC_STDOUT: - case SMARTIRC_SYSLOG: - case SMARTIRC_BROWSEROUT: - case SMARTIRC_NONE: - $this->_logdestination = $type; - break; - default: - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: unknown logdestination type ('.$type.'), will use STDOUT instead', __FILE__, __LINE__); - $this->_logdestination = SMARTIRC_STDOUT; - } - } - - /** - * Sets the file for the log if the destination is set to file. - * - * Sets the logfile, if {@link setLogdestination logdestination} is set to SMARTIRC_FILE. - * This should be only used with full path! - * - * @param string $file - * @return void - * @access public - */ - function setLogfile($file) - { - $this->_logfile = $file; - } - - /** - * Sets the delaytime before closing the socket when disconnect. - * - * @param integer $milliseconds - * @return void - * @access public - */ - function setDisconnecttime($milliseconds) - { - if (is_integer($milliseconds) && $milliseconds >= 100) { - $this->_disconnecttime = $milliseconds; - } else { - $this->_disconnecttime = 100; - } - } - - /** - * Sets the delaytime before attempting reconnect. - * Value of 0 disables the delay entirely. - * - * @param integer $milliseconds - * @return void - * @access public - */ - function setReconnectdelay($milliseconds) - { - if (is_integer($milliseconds)) { - $this->_reconnectdelay = $milliseconds; - } else { - $this->_reconnectdelay = 10000; - } - } - - /** - * Sets the delay for receiving data from the IRC server. - * - * Sets the delaytime between messages that are received, this reduces your CPU load. - * Don't set this too low (min 100ms). - * Default: 100 - * - * @param integer $milliseconds - * @return void - * @access public - */ - function setReceivedelay($milliseconds) - { - if (is_integer($milliseconds) && $milliseconds >= 100) { - $this->_receivedelay = $milliseconds; - } else { - $this->_receivedelay = 100; - } - } - - /** - * Sets the delay for sending data to the IRC server. - * - * Sets the delaytime between messages that are sent, because IRC servers doesn't like floods. - * This will avoid sending your messages too fast to the IRC server. - * Default: 250 - * - * @param integer $milliseconds - * @return void - * @access public - */ - function setSenddelay($milliseconds) - { - if (is_integer($milliseconds)) { - $this->_senddelay = $milliseconds; - } else { - $this->_senddelay = 250; - } - } - - /** - * Enables/disables autoreconnecting. - * - * @param boolean $boolean - * @return void - * @access public - */ - function setAutoReconnect($boolean) - { - if (is_bool($boolean)) { - $this->_autoreconnect = $boolean; - } else { - $this->_autoreconnect = false; - } - } - - /** - * Enables/disables autoretry for connecting to a server. - * - * @param boolean $boolean - * @return void - * @access public - */ - function setAutoRetry($boolean) - { - if (is_bool($boolean)) { - $this->_autoretry = $boolean; - } else { - $this->_autoretry = false; - } - } - - /** - * Sets the maximum number of attempts to connect to a server - * before giving up. - * - * @param integer $autoretrymax - * @return void - * @access public - */ - function setAutoRetryMax($autoretrymax) - { - if (is_integer($autoretrymax)) { - $this->_autoretrymax = $autoretrymax; - } else { - $this->_autoretrymax = 5; - } - } - - /** - * Sets the receive timeout. - * - * If the timeout occurs, the connection will be reinitialized - * Default: 300 seconds - * - * @param integer $seconds - * @return void - * @access public - */ - function setReceiveTimeout($seconds) - { - if (is_integer($seconds)) { - $this->_rxtimeout = $seconds; - } else { - $this->_rxtimeout = 300; - } - } - - /** - * Sets the transmit timeout. - * - * If the timeout occurs, the connection will be reinitialized - * Default: 300 seconds - * - * @param integer $seconds - * @return void - * @access public - */ - function setTransmitTimeout($seconds) - { - if (is_integer($seconds)) { - $this->_txtimeout = $seconds; - } else { - $this->_txtimeout = 300; - } - } - - /** - * Sets the paths for the modules. - * - * @param integer $path - * @return void - * @access public - */ - function setModulepath($path) - { - $this->_modulepath = $path; - } - - /** - * Sets wheter the script should be run as a daemon or not - * ( actually disables/enables ignore_user_abort() ) - * - * @param boolean $boolean - * @return void - * @access public - */ - function setRunAsDaemon($boolean) - { - if ($boolean === true) { - $this->_runasdaemon = true; - ignore_user_abort(true); - set_time_limit(0); - } else { - $this->_runasdaemon = false; - } - } - - /** - * Starts the benchmark (sets the counters). - * - * @return void - * @access public - */ - function startBenchmark() - { - $this->_benchmark_starttime = $this->_microint(); - $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark started', __FILE__, __LINE__); - } - - /** - * Stops the benchmark and displays the result. - * - * @return void - * @access public - */ - function stopBenchmark() - { - $this->_benchmark_stoptime = $this->_microint(); - $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark stopped', __FILE__, __LINE__); - - if ($this->_benchmark) { - $this->showBenchmark(); - } - } - - /** - * Shows the benchmark result. - * - * @return void - * @access public - */ - function showBenchmark() - { - $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark time: '.((float)$this->_benchmark_stoptime-(float)$this->_benchmark_starttime), __FILE__, __LINE__); - } - - /** - * Adds an entry to the log. - * - * Adds an entry to the log with Linux style log format. - * Possible $level constants (can also be combined with "|"s) - * SMARTIRC_DEBUG_NONE - * SMARTIRC_DEBUG_NOTICE - * SMARTIRC_DEBUG_CONNECTION - * SMARTIRC_DEBUG_SOCKET - * SMARTIRC_DEBUG_IRCMESSAGES - * SMARTIRC_DEBUG_MESSAGETYPES - * SMARTIRC_DEBUG_ACTIONHANDLER - * SMARTIRC_DEBUG_TIMEHANDLER - * SMARTIRC_DEBUG_MESSAGEHANDLER - * SMARTIRC_DEBUG_CHANNELSYNCING - * SMARTIRC_DEBUG_MODULES - * SMARTIRC_DEBUG_USERSYNCING - * SMARTIRC_DEBUG_ALL - * - * @see SMARTIRC_DEBUG_NOTICE - * @param integer $level bit constants (SMARTIRC_DEBUG_*) - * @param string $entry the new log entry - * @return void - * @access public - */ - function log($level, $entry, $file = null, $line = null) - { - // prechecks - if (!(is_integer($level)) || - !($level & SMARTIRC_DEBUG_ALL)) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: invalid log level passed to log() ('.$level.')', __FILE__, __LINE__); - return; - } - - if (!($level & $this->_debug) || - ($this->_logdestination == SMARTIRC_NONE)) { - return; - } - - if (substr($entry, -1) != "\n") { - $entry .= "\n"; - } - - if ($file !== null && - $line !== null) { - $file = basename($file); - $entry = $file.'('.$line.') '.$entry; - } else { - $entry = 'unknown(0) '.$entry; - } - - $formatedentry = date('M d H:i:s ').$entry; - switch ($this->_logdestination) { - case SMARTIRC_STDOUT: - echo $formatedentry; - flush(); - break; - case SMARTIRC_BROWSEROUT: - echo '
'.htmlentities($formatedentry).'
'; - break; - case SMARTIRC_FILE: - if (!is_resource($this->_logfilefp)) { - if ($this->_logfilefp === null) { - // we reconncted and don't want to destroy the old log entries - $this->_logfilefp = fopen($this->_logfile,'a'); - } else { - $this->_logfilefp = fopen($this->_logfile,'w'); - } - } - fwrite($this->_logfilefp, $formatedentry); - fflush($this->_logfilefp); - break; - case SMARTIRC_SYSLOG: - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - define_syslog_variables(); - } - if (!is_int($this->_logfilefp)) { - $this->_logfilefp = openlog('Net_SmartIRC', LOG_NDELAY, LOG_DAEMON); - } - syslog(LOG_INFO, $entry); - break; - } - } - - /** - * Returns the full motd. - * - * @return array - * @access public - */ - function getMotd() - { - return $this->_motd; - } - - /** - * Returns the usermode. - * - * @return string - * @access public - */ - function getUsermode() - { - return $this->_usermode; - } - - /** - * Returns a reference to the channel object of the specified channelname. - * - * @param string $channelname - * @return object - * @access public - */ - function &getChannel($channelname) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: getChannel() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($this->isJoined($channelname)) { - return $this->_channels[strtolower($channelname)]; - } else { - return false; - } - } - - /** - * Returns a reference to the user object for the specified username and channelname. - * - * @param string $channelname - * @param string $username - * @return object - * @access public - */ - function &getUser($channelname, $username) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: getUser() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($this->isJoined($channelname, $username)) { - return $this->_channels[strtolower($channelname)]->users[strtolower($username)]; - } else { - return false; - } - } - - /** - * Creates the sockets and connects to the IRC server on the given port. - * - * @param string $address - * @param integer $port - * @return boolean - * @access public - */ - function connect($address, $port) - { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connecting', __FILE__, __LINE__); - $this->_address = $address; - $this->_port = $port; - - if ($this->_usesockets == true) { - $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: using real sockets', __FILE__, __LINE__); - $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($this->_bindaddress !== null) { - if (socket_bind($this->_socket, $this->_bindaddress, $this->_bindport)) { - $this->log(SMARTIRC_DEBUG_SOCKET, - 'DEBUG_SOCKET: bound to '.$this->_bindaddress.':' - .$this->_bindport, __FILE__, __LINE__); - } else { - $errno = socket_last_error($this->_socket); - $error_msg = 'ERROR: Unable to bind '.$this->_bindaddress.':' - .$this->_bindport.' reason: '.socket_strerror($errno) - .' ('.$errno.')'; - $this->log(SMARTIRC_DEBUG_NOTICE, - 'DEBUG_NOTICE: '.$error_msg, __FILE__, __LINE__); - echo $error_msg . PHP_EOL; - return false; - } - } - $result = @socket_connect($this->_socket, $this->_address, $this->_port); - } else { - $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: using fsockets', __FILE__, __LINE__); - $result = fsockopen($this->_address, $this->_port, $errno, $errstr); - } - - if ($result === false) { - if ($this->_usesockets == true) { - $error = socket_strerror(socket_last_error($this->_socket)); - } else { - $error = $errstr.' ('.$errno.')'; - } - - $error_msg = 'couldn\'t connect to "'.$address.'" reason: "'.$error.'"'; - $this->log(SMARTIRC_DEBUG_NOTICE, 'DEBUG_NOTICE: '.$error_msg, __FILE__, __LINE__); - // TODO! needs to be return value - //$this->throwError($error_msg); // This returns, preventing reconnect. - - if (($this->_autoretry == true) && - ($this->_autoretrycount < $this->_autoretrymax)) { - echo 'ERROR connecting to (' . - $address . - ':' . - $port . - ') error: (' . - $error . - ') retry (' . - $this->_autoretrycount . - '/' . - $this->_autoretrymax . - '). Sleeping for (' . - $this->_reconnectdelay . - ') ms.' . - PHP_EOL; - $this->_delayReconnect(); - $this->_autoretrycount++; - $this->reconnect(); - } else { - echo 'ERROR connecting to (' . - $address . - ':' . - $port . - ') after (' . - $this->_autoretrymax . - ') retries, error: (' . - $error . - ').' . - PHP_EOL; - return false; - } - } else { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connected', __FILE__, __LINE__); - $this->_autoretrycount = 0; - $this->_connectionerror = false; - - if ($this->_usesockets != true) { - $this->_socket = $result; - $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: activating nonblocking fsocket mode', __FILE__, __LINE__); - stream_set_blocking($this->_socket, 0); - } - } - - $this->_lastrx = time(); - $this->_lasttx = $this->_lastrx; - $this->_updatestate(); - - return $result !== false; - } - - /** - * Disconnects from the IRC server nicely with a QUIT or just destroys the socket. - * - * Disconnects from the IRC server in the given quickness mode. - * $quickdisconnect: - * true, just close the socket - * false, send QUIT and wait {@link $_disconnectime $_disconnectime} before closing the socket - * - * @param boolean $quickdisconnect default: false - * @return boolean - * @access public - */ - function disconnect($quickdisconnect = false) - { - if ($this->_state() == SMARTIRC_STATE_CONNECTED) { - if ($quickdisconnect == false) { - $this->_send('QUIT', SMARTIRC_CRITICAL); - usleep($this->_disconnecttime*1000); - } - - if ($this->_usesockets == true) { - @socket_shutdown($this->_socket); - @socket_close($this->_socket); - } else { - fclose($this->_socket); - } - - $this->_updatestate(); - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: disconnected', __FILE__, __LINE__); - } else { - return false; - } - - if ($this->_channelsyncing == true) { - // let's clean our channel array - $this->_channels = array(); - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: cleaned channel array', __FILE__, __LINE__); - } - - if ($this->_usersyncing == true) { - // let's clean our user array - $this->_users = array(); - $this->log(SMARTIRC_DEBUG_USERSYNCING, 'DEBUG_USERSYNCING: cleaned user array', __FILE__, __LINE__); - } - - if ($this->_logdestination == SMARTIRC_FILE) { - fclose($this->_logfilefp); - $this->_logfilefp = null; - } else if ($this->_logdestination == SMARTIRC_SYSLOG) { - closelog(); - } - - return true; - } - - /** - * Reconnects to the IRC server with the same login info, - * it also rejoins the channels - * - * @return void - * @access public - */ - function reconnect() - { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: reconnecting...', __FILE__, __LINE__); - - // remember in which channels we are joined - $channels = array(); - foreach ($this->_channels as $value) { - if (empty($value->key)) { - $channels[] = array('name' => $value->name); - } else { - $channels[] = array('name' => $value->name, 'key' => $value->key); - } - } - - $this->disconnect(true); - $this->connect($this->_address, $this->_port); - $this->login($this->_nick, $this->_realname, $this->_usermode, $this->_username, $this->_password); - - // rejoin the channels - foreach ($channels as $value) { - if (isset($value['key'])) { - $this->join($value['name'], $value['key']); - } else { - $this->join($value['name']); - } - } - } - - /** - * login and register nickname on the IRC network - * - * Registers the nickname and user information on the IRC network. - * - * @param string $nick - * @param string $realname - * @param integer $usermode - * @param string $username - * @param string $password - * @return void - * @access public - */ - function login($nick, $realname, $usermode = 0, $username = null, $password = null) - { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: logging in', __FILE__, __LINE__); - - $this->_nick = str_replace(' ', '', $nick); - $this->_realname = $realname; - - if ($username !== null) { - $this->_username = str_replace(' ', '', $username); - } else { - $this->_username = str_replace(' ', '', exec('whoami')); - } - - if ($password !== null) { - $this->_password = $password; - $this->_send('PASS '.$this->_password, SMARTIRC_CRITICAL); - } - - if (!is_numeric($usermode)) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'DEBUG_NOTICE: login() usermode ('.$usermode.') is not valid, will use 0 instead', __FILE__, __LINE__); - $usermode = 0; - } - - $this->_send('NICK '.$this->_nick, SMARTIRC_CRITICAL); - $this->_send('USER '.$this->_username.' '.$usermode.' '.SMARTIRC_UNUSED.' :'.$this->_realname, SMARTIRC_CRITICAL); - - if (count($this->_performs)) { - // if we have extra commands to send, do it now - foreach($this->_performs as $command) { - $this->_send($command, SMARTIRC_HIGH); - } - // if we sent "ns auth" commands, we may need to resend our nick - $this->_send('NICK '.$this->_nick, SMARTIRC_HIGH); - } - } - - // - - /** - * adds a command to the list of commands to be sent after login() info - * - * @param string $cmd the command to add to the perform list - * @access public - */ - function perform($cmd) - { - $this->_performs[] = $cmd; - } - - /** - * checks if the passed nickname is our own nickname - * - * @param string $nickname - * @return boolean - * @access public - */ - function isMe($nickname) - { - if ($nickname == $this->_nick) { - return true; - } else { - return false; - } - } - - /** - * checks if we or the given user is joined to the specified channel and returns the result - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $nickname - * @return boolean - * @access public - */ - function isJoined($channel, $nickname = null) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isJoined() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($nickname === null) { - $nickname = $this->_nick; - } - - if (isset($this->_channels[strtolower($channel)]->users[strtolower($nickname)])) { - return true; - } - - return false; - } - - /** - * Checks if we or the given user is founder on the specified channel and returns the result. - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $nickname - * @return boolean - * @access public - */ - function isFounder($channel, $nickname = null) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isFounder() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($nickname === null) { - $nickname = $this->_nick; - } - - if ($this->isJoined($channel, $nickname)) { - if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->founder) { - return true; - } - } - - return false; - } - - /** - * Checks if we or the given user is admin on the specified channel and returns the result. - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $nickname - * @return boolean - * @access public - */ - function isAdmin($channel, $nickname = null) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isAdmin() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($nickname === null) { - $nickname = $this->_nick; - } - - if ($this->isJoined($channel, $nickname)) { - if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->admin) { - return true; - } - } - - return false; - } - - /** - * Checks if we or the given user is opped on the specified channel and returns the result. - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $nickname - * @return boolean - * @access public - */ - function isOpped($channel, $nickname = null) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isOpped() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($nickname === null) { - $nickname = $this->_nick; - } - - if ($this->isJoined($channel, $nickname)) { - if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->op) { - return true; - } - } - - return false; - } - - /** - * Checks if we or the given user is hopped on the specified channel and returns the result. - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $nickname - * @return boolean - * @access public - */ - function isHopped($channel, $nickname = null) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isHopped() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($nickname === null) { - $nickname = $this->_nick; - } - - if ($this->isJoined($channel, $nickname)) { - if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->hop) { - return true; - } - } - - return false; - } - - /** - * Checks if we or the given user is voiced on the specified channel and returns the result. - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $nickname - * @return boolean - * @access public - */ - function isVoiced($channel, $nickname = null) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isVoiced() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($nickname === null) { - $nickname = $this->_nick; - } - - if ($this->isJoined($channel, $nickname)) { - if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->voice) { - return true; - } - } - - return false; - } - - /** - * Checks if the hostmask is on the specified channel banned and returns the result. - * ChannelSyncing is required for this. - * - * @see setChannelSyncing - * @param string $channel - * @param string $hostmask - * @return boolean - * @access public - */ - function isBanned($channel, $hostmask) - { - if ($this->_channelsyncing != true) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isBanned() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); - return false; - } - - if ($this->isJoined($channel)) { - $result = array_search($hostmask, $this->_channels[strtolower($channel)]->bans); - - if ($result !== false) { - return true; - } - } - - return false; - } - - /** - * goes into receive mode - * - * Goes into receive and idle mode. Only call this if you want to "spawn" the bot. - * No further lines of PHP code will be processed after this call, only the bot methods! - * - * @return boolean - * @access public - */ - function listen() - { - while ($this->_state() == SMARTIRC_STATE_CONNECTED) { - $this->listenOnce(); - } - - return false; - } - - /** - * goes into receive mode _only_ for one pass - * - * Goes into receive mode. It will return when one pass is complete. - * Use this when you want to connect to multiple IRC servers. - * - * @return boolean - * @access public - */ - function listenOnce() - { - if ($this->_state() == SMARTIRC_STATE_CONNECTED) { - $this->_rawreceive(); - if ($this->_connectionerror) { - if ($this->_autoreconnect) { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connection error detected, will reconnect!', __FILE__, __LINE__); - $this->reconnect(); - } else { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connection error detected, will disconnect!', __FILE__, __LINE__); - $this->disconnect(); - } - } - return true; - } else { - return false; - } - } - - /** - * waits for a special message type and puts the answer in $result - * - * Creates a special actionhandler for that given TYPE and returns the answer. - * This will only receive the requested type, immediately quit and disconnect from the IRC server. - * Made for showing IRC statistics on your homepage, or other IRC related information. - * - * @param integer $messagetype see in the documentation 'Message Types' - * @return array answer from the IRC server for this $messagetype - * @access public - */ - function listenFor($messagetype) - { - $listenfor = new Net_SmartIRC_listenfor(); - $this->registerActionhandler($messagetype, '.*', $listenfor, 'handler'); - $this->listen(); - $result = $listenfor->result; - - if (isset($listenfor)) { - unset($listenfor); - } - - return $result; - } - - /** - * registers a new actionhandler and returns the assigned id - * - * Registers an actionhandler in Net_SmartIRC for calling it later. - * The actionhandler id is needed for unregistering the actionhandler. - * - * @see example.php - * @param integer $handlertype bits constants, see in this documentation Message Types - * @param string $regexhandler the message that has to be in the IRC message in regex syntax - * @param object $object a reference to the objects of the method - * @param string $methodname the methodname that will be called when the handler happens - * @return integer assigned actionhandler id - * @access public - */ - function registerActionhandler($handlertype, $regexhandler, &$object, $methodname) - { - // precheck - if (!$this->_isValidType($handlertype)) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: passed invalid handlertype to registerActionhandler()', __FILE__, __LINE__); - return false; - } - - $id = $this->_actionhandlerid++; - $newactionhandler = new Net_SmartIRC_actionhandler(); - - $newactionhandler->id = $id; - $newactionhandler->type = $handlertype; - $newactionhandler->message = $regexhandler; - $newactionhandler->object = &$object; - $newactionhandler->method = $methodname; - - $this->_actionhandler[] = &$newactionhandler; - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') registered', __FILE__, __LINE__); - return $id; - } - - /** - * unregisters an existing actionhandler - * - * @param integer $handlertype - * @param string $regexhandler - * @param object $object - * @param string $methodname - * @return boolean - * @access public - */ - function unregisterActionhandler($handlertype, $regexhandler, &$object, $methodname) - { - // precheck - if (!$this->_isValidType($handlertype)) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: passed invalid handlertype to unregisterActionhandler()', __FILE__, __LINE__); - return false; - } - - $handler = &$this->_actionhandler; - $handlercount = count($handler); - - for ($i = 0; $i < $handlercount; $i++) { - $handlerobject = &$handler[$i]; - - if ($handlerobject->type == $handlertype && - $handlerobject->message == $regexhandler && - $handlerobject->method == $methodname) { - - $id = $handlerobject->id; - - if (isset($this->_actionhandler[$i])) { - unset($this->_actionhandler[$i]); - } - - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered', __FILE__, __LINE__); - $this->_reorderactionhandler(); - return true; - } - } - - $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__); - return false; - } - - /** - * unregisters an existing actionhandler via the id - * - * @param integer $id - * @return boolean - * @access public - */ - function unregisterActionid($id) - { - $handler = &$this->_actionhandler; - $handlercount = count($handler); - for ($i = 0; $i < $handlercount; $i++) { - $handlerobject = &$handler[$i]; - - if ($handlerobject->id == $id) { - if (isset($this->_actionhandler[$i])) { - unset($this->_actionhandler[$i]); - } - - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered', __FILE__, __LINE__); - $this->_reorderactionhandler(); - return true; - } - } - - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: could not find actionhandler id: '.$id.' _not_ unregistered', __FILE__, __LINE__); - return false; - } - - /** - * registers a timehandler and returns the assigned id - * - * Registers a timehandler in Net_SmartIRC, which will be called in the specified interval. - * The timehandler id is needed for unregistering the timehandler. - * - * @see example7.php - * @param integer $interval interval time in milliseconds - * @param object $object a reference to the objects of the method - * @param string $methodname the methodname that will be called when the handler happens - * @return integer assigned timehandler id - * @access public - */ - function registerTimehandler($interval, &$object, $methodname) - { - $id = $this->_timehandlerid++; - $newtimehandler = new Net_SmartIRC_timehandler(); - - $newtimehandler->id = $id; - $newtimehandler->interval = $interval; - $newtimehandler->object = &$object; - $newtimehandler->method = $methodname; - $newtimehandler->lastmicrotimestamp = $this->_microint(); - - $this->_timehandler[] = &$newtimehandler; - $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: timehandler('.$id.') registered', __FILE__, __LINE__); - - if (($interval < $this->_mintimer) || ($this->_mintimer == false)) { - $this->_mintimer = $interval; - } - - return $id; - } - - /** - * unregisters an existing timehandler via the id - * - * @see example7.php - * @param integer $id - * @return boolean - * @access public - */ - function unregisterTimeid($id) - { - $handler = &$this->_timehandler; - $handlercount = count($handler); - for ($i = 0; $i < $handlercount; $i++) { - $handlerobject = &$handler[$i]; - - if ($handlerobject->id == $id) { - if (isset($this->_timehandler[$i])) { - unset($this->_timehandler[$i]); - } - - $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: timehandler('.$id.') unregistered', __FILE__, __LINE__); - $this->_reordertimehandler(); - $this->_updatemintimer(); - return true; - } - } - - $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: could not find timehandler id: '.$id.' _not_ unregistered', __FILE__, __LINE__); - return false; - } - - function loadModule($name) - { - // is the module already loaded? - if (in_array($name, $this->_modules)) { - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING! module with the name "'.$name.'" already loaded!', __FILE__, __LINE__); - return false; - } - - $filename = $this->_modulepath.'/'.$name.'.php'; - if (!file_exists($filename)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: couldn\'t load module "'.$filename.'" file doesn\'t exist', __FILE__, __LINE__); - return false; - } - - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: loading module: "'.$name.'"...', __FILE__, __LINE__); - // pray that there is no parse error, it will kill us! - include_once($filename); - $classname = 'Net_SmartIRC_module_'.$name; - - if (!class_exists($classname)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: class '.$classname.' not found in '.$filename, __FILE__, __LINE__); - return false; - } - - $methods = get_class_methods($classname); - if (!in_array('__construct', $methods) && !in_array('module_init', $methods)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required method'.$classname.'::__construct not found, aborting...', __FILE__, __LINE__); - return false; - } - - if (!in_array('__destruct', $methods) && !in_array('module_exit', $methods)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required method'.$classname.'::__destruct not found, aborting...', __FILE__, __LINE__); - return false; - } - - $vars = array_keys(get_class_vars($classname)); - if (!in_array('name', $vars)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::name not found, aborting...', __FILE__, __LINE__); - return false; - } - - if (!in_array('description', $vars)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::description not found, aborting...', __FILE__, __LINE__); - return false; - } - - if (!in_array('author', $vars)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::author not found, aborting...', __FILE__, __LINE__); - return false; - } - - if (!in_array('license', $vars)) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::license not found, aborting...', __FILE__, __LINE__); - return false; - } - - // looks like the module satisfies us, so instantiate it - if (in_array('module_init', $methods)) { - // we're using an old module_init style module - $module = new $classname; - } else if (func_num_args() == 1) { - // we're using a new __construct style module, which maintains its - // own reference to the $irc client object it's being used on - $module = new $classname($this); - } else { - // we're using new style AND we have args to pass to the constructor - if (func_num_args() == 2) { - // only one arg, so pass it as is - $module = new $classname($this, func_get_arg(1)); - } else { - // multiple args, so pass them in an array - $module = new $classname($this, array_slice(func_get_args(), 1)); - } - } - - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: successfully created' - .' instance of: '.$classname, __FILE__, __LINE__ - ); - - // check for deprecated init function and run it if it exists - if (in_array('module_init', get_class_methods($classname))) { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: calling ' - .$classname.'::module_init()', __FILE__, __LINE__ - ); - $module->module_init($this); - } - - $this->_modules[$name] = &$module; - - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: successfully loaded' - .' module: '.$name, __FILE__, __LINE__ - ); - return true; - } - - function unloadModule($name) - { - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: unloading module: '.$name.'...', __FILE__, __LINE__); - - $modules_keys = array_keys($this->_modules); - $modulecount = count($modules_keys); - for ($i = 0; $i < $modulecount; $i++) { - $module = &$this->_modules[$modules_keys[$i]]; - $modulename = strtolower(get_class($module)); - - if ($modulename == 'net_smartirc_module_'.$name) { - if (in_array('module_exit', get_class_methods($modulename))) { - $module->module_exit($this); - } - unset($this->_modules[$i]); // should call __destruct() on it - $this->_reordermodules(); - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: successfully' - .' unloaded module: '.$name, __FILE__, __LINE__); - return true; - } - } - - $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: couldn\'t unload' - .' module: '.$name.' (it\'s not loaded!)', __FILE__, __LINE__ - ); - return false; - } - - // - /** - * changes a already used nickname to a new nickname plus 3 random digits - * - * @return void - * @access private - */ - function _nicknameinuse() - { - $newnickname = substr($this->_nick, 0, 5).rand(0, 999); - $this->changeNick($newnickname, SMARTIRC_CRITICAL); - } - - /** - * sends an IRC message - * - * Adds a message to the messagequeue, with the optional priority. - * $priority: - * SMARTIRC_CRITICAL - * SMARTIRC_HIGH - * SMARTIRC_MEDIUM - * SMARTIRC_LOW - * - * @param string $data - * @param integer $priority must be one of the priority constants - * @return boolean - * @access public - */ - function send($data, $priority = SMARTIRC_MEDIUM) - { - return $this->_send($data, $priority); - } - - /** - * sends an IRC message - * - * Adds a message to the messagequeue, with the optional priority. - * $priority: - * SMARTIRC_CRITICAL - * SMARTIRC_HIGH - * SMARTIRC_MEDIUM - * SMARTIRC_LOW - * - * @param string $data - * @param integer $priority must be one of the priority constants - * @return boolean - * @access private - */ - function _send($data, $priority = SMARTIRC_MEDIUM) - { - switch ($priority) { - case SMARTIRC_CRITICAL: - $this->_rawsend($data); - break; - case SMARTIRC_HIGH: - case SMARTIRC_MEDIUM: - case SMARTIRC_LOW: - $this->_messagebuffer[$priority][] = $data; - break; - default: - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: message ('.$data.') with an invalid priority passed ('.$priority.'), message is ignored!', __FILE__, __LINE__); - return false; - } - - return true; - } - - /** - * checks the buffer if there are messages to send - * - * @return void - * @access private - */ - function _checkbuffer() - { - if (!$this->_loggedin) { - return; - } - - static $highsent = 0; - static $lastmicrotimestamp = 0; - - if ($lastmicrotimestamp == 0) { - $lastmicrotimestamp = $this->_microint(); - } - - $highcount = count($this->_messagebuffer[SMARTIRC_HIGH]); - $mediumcount = count($this->_messagebuffer[SMARTIRC_MEDIUM]); - $lowcount = count($this->_messagebuffer[SMARTIRC_LOW]); - $this->_messagebuffersize = $highcount+$mediumcount+$lowcount; - - // don't send them too fast - if ($this->_microint() >= ($lastmicrotimestamp+($this->_senddelay/1000))) { - $result = null; - if ($highcount > 0 && $highsent <= 2) { - $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_HIGH])); - $lastmicrotimestamp = $this->_microint(); - $highsent++; - } else if ($mediumcount > 0) { - $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_MEDIUM])); - $lastmicrotimestamp = $this->_microint(); - $highsent = 0; - } else if ($lowcount > 0) { - $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_LOW])); - $lastmicrotimestamp = $this->_microint(); - } - } - } - - /** - * Checks the running timers and calls the registered timehandler, - * when the interval is reached. - * - * @return void - * @access private - */ - function _checktimer() - { - if (!$this->_loggedin) { - return; - } - - // has to be count() because the array may change during the loop! - for ($i = 0; $i < count($this->_timehandler); $i++) { - $handlerobject = &$this->_timehandler[$i]; - $microtimestamp = $this->_microint(); - if ($microtimestamp >= ($handlerobject->lastmicrotimestamp+($handlerobject->interval/1000))) { - $methodobject = &$handlerobject->object; - $method = $handlerobject->method; - $handlerobject->lastmicrotimestamp = $microtimestamp; - - if (@method_exists($methodobject, $method)) { - $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__); - $methodobject->$method($this); - } - } - } - } - - /** - * Checks if a receive or transmit timeout occured and reconnects if configured - * - * @return void - * @access private - */ - function _checktimeout() - { - if ($this->_autoreconnect == true) { - $timestamp = time(); - if ($this->_lastrx < ($timestamp - $this->_rxtimeout)) { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: receive timeout detected, doing reconnect...', __FILE__, __LINE__); - $this->_delayReconnect(); - $this->reconnect(); - } else if ($this->_lasttx < ($timestamp - $this->_txtimeout)) { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: transmit timeout detected, doing reconnect...', __FILE__, __LINE__); - $this->_delayReconnect(); - $this->reconnect(); - } - } - } - - /** - * sends a raw message to the IRC server (don't use this!!) - * - * Use message() or send() instead. - * - * @param string $data - * @return boolean - * @access private - */ - function _rawsend($data) - { - if ($this->_state() == SMARTIRC_STATE_CONNECTED) { - $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: sent: "'.$data.'"', __FILE__, __LINE__); - - if ($this->_usesockets == true) { - $result = socket_write($this->_socket, $data.SMARTIRC_CRLF); - } else { - $result = fwrite($this->_socket, $data.SMARTIRC_CRLF); - } - - - if ($result === false) { - // writing to the socket failed, means the connection is broken - $this->_connectionerror = true; - - return false; - } else { - $this->_lasttx = time(); - return true; - } - } else { - return false; - } - } - - /** - * goes into main receive mode _once_ per call and waits for messages from the IRC server - * - * @return void - * @access private - */ - function _rawreceive() - { - $lastpart = ''; - $rawdataar = array(); - - $this->_checkbuffer(); - - $timeout = $this->_selecttimeout(); - if ($this->_usesockets == true) { - $sread = array($this->_socket); - // this will trigger a warning when catching a signal - $result = @socket_select($sread, $w = null, $e = null, 0, $timeout*1000); - - if ($result == 1) { - // the socket got data to read - $rawdata = socket_read($this->_socket, 10240); - } else if ($result === false) { - if (socket_last_error() == 4) { - // we got hit with a SIGHUP signal - $rawdata = null; - global $bot; - - if (is_callable(array($bot, 'reload'))) { - $bot->reload(); - } - } else { - // panic! panic! something went wrong! - $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket_select() returned false, something went wrong! Reason: '.socket_strerror(socket_last_error()), __FILE__, __LINE__); - exit; - } - } else { - // no data - $rawdata = null; - } - } else { - usleep($this->_receivedelay*1000); - $rawdata = fread($this->_socket, 10240); - } - if ($rawdata === false) { - // reading from the socket failed, the connection is broken - $this->_connectionerror = true; - } - - $this->_checktimer(); - $this->_checktimeout(); - - if ($rawdata !== null && !empty($rawdata)) { - $this->_lastrx = time(); - $rawdata = str_replace("\r", '', $rawdata); - $rawdata = $lastpart.$rawdata; - - $lastpart = substr($rawdata, strrpos($rawdata ,"\n")+1); - $rawdata = substr($rawdata, 0, strrpos($rawdata ,"\n")); - $rawdataar = explode("\n", $rawdata); - } - - // loop through our received messages - while (count($rawdataar) > 0) { - $rawline = array_shift($rawdataar); - $validmessage = false; - - $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: received: "'.$rawline.'"', __FILE__, __LINE__); - - // building our data packet - $ircdata = new Net_SmartIRC_data(); - $ircdata->rawmessage = $rawline; - $lineex = explode(' ', $rawline); - $ircdata->rawmessageex = $lineex; - $messagecode = $lineex[0]; - - if (substr($rawline, 0, 1) == ':') { - $validmessage = true; - $line = substr($rawline, 1); - $lineex = explode(' ', $line); - - // conform to RFC 2812 - $from = $lineex[0]; - $messagecode = $lineex[1]; - $exclamationpos = strpos($from, '!'); - $atpos = strpos($from, '@'); - $colonpos = strpos($line, ' :'); - if ($colonpos !== false) { - // we want the exact position of ":" not beginning from the space - $colonpos += 1; - } - $ircdata->nick = substr($from, 0, $exclamationpos); - $ircdata->ident = substr($from, $exclamationpos+1, ($atpos-$exclamationpos)-1); - $ircdata->host = substr($from, $atpos+1); - $ircdata->type = $this->_gettype($rawline); - $ircdata->from = $from; - if ($colonpos !== false) { - $ircdata->message = substr($line, $colonpos+1); - $ircdata->messageex = explode(' ', $ircdata->message); - } - - if ($ircdata->type & (SMARTIRC_TYPE_CHANNEL| - SMARTIRC_TYPE_ACTION| - SMARTIRC_TYPE_MODECHANGE| - SMARTIRC_TYPE_TOPICCHANGE| - SMARTIRC_TYPE_KICK| - SMARTIRC_TYPE_PART| - SMARTIRC_TYPE_JOIN)) { - $ircdata->channel = $lineex[2]; - } else if ($ircdata->type & (SMARTIRC_TYPE_WHO| - SMARTIRC_TYPE_BANLIST| - SMARTIRC_TYPE_TOPIC| - SMARTIRC_TYPE_CHANNELMODE)) { - $ircdata->channel = $lineex[3]; - } else if ($ircdata->type & SMARTIRC_TYPE_NAME) { - $ircdata->channel = $lineex[4]; - } - - if ($ircdata->channel !== null) { - if (substr($ircdata->channel, 0, 1) == ':') { - $ircdata->channel = substr($ircdata->channel, 1); - } - } - - $this->log(SMARTIRC_DEBUG_MESSAGEPARSER, 'DEBUG_MESSAGEPARSER: ircdata nick: "'.$ircdata->nick. - '" ident: "'.$ircdata->ident. - '" host: "'.$ircdata->host. - '" type: "'.$ircdata->type. - '" from: "'.$ircdata->from. - '" channel: "'.$ircdata->channel. - '" message: "'.$ircdata->message. - '"', __FILE__, __LINE__); - } - - // lets see if we have a messagehandler for it - $this->_handlemessage($messagecode, $ircdata); - - if ($validmessage == true) { - // now the actionhandlers are comming - $this->_handleactionhandler($ircdata); - } - - if (isset($ircdata)) { - unset($ircdata); - } - } - } - - /** - * sends the pong for keeping alive - * - * Sends the PONG signal as reply of the PING from the IRC server. - * - * @param string $data - * @return void - * @access private - */ - function _pong($data) - { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: Ping? Pong!', __FILE__, __LINE__); - $this->_send('PONG '.$data, SMARTIRC_CRITICAL); - } - - /** - * returns the calculated selecttimeout value - * - * @return integer selecttimeout in microseconds - * @access private - */ - function _selecttimeout() - { - if ($this->_messagebuffersize == 0) { - $this->_selecttimeout = null; - - if ($this->_mintimer != false) { - $this->_calculateselecttimeout($this->_mintimer); - } - - if ($this->_autoreconnect == true) { - $this->_calculateselecttimeout($this->_rxtimeout*1000); - } - - $this->_calculateselecttimeout($this->_maxtimer); - return $this->_selecttimeout; - } else { - return $this->_senddelay; - } - } - - /** - * calculates the selecttimeout value - * - * @return void - * @access private - */ - function _calculateselecttimeout($microseconds) - { - if (($this->_selecttimeout > $microseconds) || $this->_selecttimeout === null) { - $this->_selecttimeout = $microseconds; - } - } - - /** - * updates _mintimer to the smallest timer interval - * - * @return void - * @access private - */ - function _updatemintimer() - { - $timerarray = array(); - foreach ($this->_timehandler as $values) { - $timerarray[] = $values->interval; - } - - $result = array_multisort($timerarray, SORT_NUMERIC, SORT_ASC); - if ($result == true && isset($timerarray[0])) { - $this->_mintimer = $timerarray[0]; - } else { - $this->_mintimer = false; - } - } - - /** - * reorders the actionhandler array, needed after removing one - * - * @return void - * @access private - */ - function _reorderactionhandler() - { - $orderedactionhandler = array(); - foreach ($this->_actionhandler as $value) { - $orderedactionhandler[] = $value; - } - $this->_actionhandler = &$orderedactionhandler; - } - - /** - * reorders the timehandler array, needed after removing one - * - * @return void - * @access private - */ - function _reordertimehandler() - { - $orderedtimehandler = array(); - foreach ($this->_timehandler as $value) { - $orderedtimehandler[] = $value; - } - $this->_timehandler = &$orderedtimehandler; - } - - /** - * reorders the modules array, needed after removing one - * - * @return void - * @access private - */ - function _reordermodules() - { - $orderedmodules = array(); - foreach ($this->_modules as $value) { - $orderedmodules[] = $value; - } - $this->_modules = &$orderedmodules; - } - - /** - * determines the messagetype of $line - * - * Analyses the type of an IRC message and returns the type. - * - * @param string $line - * @return integer SMARTIRC_TYPE_* constant - * @access private - */ - function _gettype($line) - { - if (preg_match('/^:[^ ]+? [0-9]{3} .+$/', $line) == 1) { - $lineex = explode(' ', $line); - $code = $lineex[1]; - - switch ($code) { - case SMARTIRC_RPL_WELCOME: - case SMARTIRC_RPL_YOURHOST: - case SMARTIRC_RPL_CREATED: - case SMARTIRC_RPL_MYINFO: - case SMARTIRC_RPL_BOUNCE: - return SMARTIRC_TYPE_LOGIN; - case SMARTIRC_RPL_LUSERCLIENT: - case SMARTIRC_RPL_LUSEROP: - case SMARTIRC_RPL_LUSERUNKNOWN: - case SMARTIRC_RPL_LUSERME: - case SMARTIRC_RPL_LUSERCHANNELS: - return SMARTIRC_TYPE_INFO; - case SMARTIRC_RPL_MOTDSTART: - case SMARTIRC_RPL_MOTD: - case SMARTIRC_RPL_ENDOFMOTD: - return SMARTIRC_TYPE_MOTD; - case SMARTIRC_RPL_NAMREPLY: - case SMARTIRC_RPL_ENDOFNAMES: - return SMARTIRC_TYPE_NAME; - case SMARTIRC_RPL_WHOREPLY: - case SMARTIRC_RPL_ENDOFWHO: - return SMARTIRC_TYPE_WHO; - case SMARTIRC_RPL_LISTSTART: - return SMARTIRC_TYPE_NONRELEVANT; - case SMARTIRC_RPL_LIST: - case SMARTIRC_RPL_LISTEND: - return SMARTIRC_TYPE_LIST; - case SMARTIRC_RPL_BANLIST: - case SMARTIRC_RPL_ENDOFBANLIST: - return SMARTIRC_TYPE_BANLIST; - case SMARTIRC_RPL_TOPIC: - return SMARTIRC_TYPE_TOPIC; - case SMARTIRC_RPL_WHOISUSER: - case SMARTIRC_RPL_WHOISSERVER: - case SMARTIRC_RPL_WHOISOPERATOR: - case SMARTIRC_RPL_WHOISIDLE: - case SMARTIRC_RPL_ENDOFWHOIS: - case SMARTIRC_RPL_WHOISCHANNELS: - return SMARTIRC_TYPE_WHOIS; - case SMARTIRC_RPL_WHOWASUSER: - case SMARTIRC_RPL_ENDOFWHOWAS: - return SMARTIRC_TYPE_WHOWAS; - case SMARTIRC_RPL_UMODEIS: - return SMARTIRC_TYPE_USERMODE; - case SMARTIRC_RPL_CHANNELMODEIS: - return SMARTIRC_TYPE_CHANNELMODE; - case SMARTIRC_ERR_NICKNAMEINUSE: - case SMARTIRC_ERR_NOTREGISTERED: - return SMARTIRC_TYPE_ERROR; - default: - $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: replycode UNKNOWN ('.$code.'): "'.$line.'"', __FILE__, __LINE__); - } - } - - if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'ACTION .*'.chr(1).'$/', $line) == 1) { - return SMARTIRC_TYPE_ACTION; - } else if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'.*'.chr(1).'$/', $line) == 1) { - return (SMARTIRC_TYPE_CTCP_REQUEST|SMARTIRC_TYPE_CTCP); - } else if (preg_match('/^:.*? NOTICE .* :'.chr(1).'.*'.chr(1).'$/', $line) == 1) { - return (SMARTIRC_TYPE_CTCP_REPLY|SMARTIRC_TYPE_CTCP); - } else if (preg_match('/^:.*? PRIVMSG (\&|\#|\+|\!).* :.*$/', $line) == 1) { - return SMARTIRC_TYPE_CHANNEL; - } else if (preg_match('/^:.*? PRIVMSG .*:.*$/', $line) == 1) { - return SMARTIRC_TYPE_QUERY; - } else if (preg_match('/^:.*? NOTICE .* :.*$/', $line) == 1) { - return SMARTIRC_TYPE_NOTICE; - } else if (preg_match('/^:.*? INVITE .* .*$/', $line) == 1) { - return SMARTIRC_TYPE_INVITE; - } else if (preg_match('/^:.*? JOIN .*$/', $line) == 1) { - return SMARTIRC_TYPE_JOIN; - } else if (preg_match('/^:.*? TOPIC .* :.*$/', $line) == 1) { - return SMARTIRC_TYPE_TOPICCHANGE; - } else if (preg_match('/^:.*? NICK .*$/', $line) == 1) { - return SMARTIRC_TYPE_NICKCHANGE; - } else if (preg_match('/^:.*? KICK .* .*$/', $line) == 1) { - return SMARTIRC_TYPE_KICK; - } else if (preg_match('/^:.*? PART .*$/', $line) == 1) { - return SMARTIRC_TYPE_PART; - } else if (preg_match('/^:.*? MODE .* .*$/', $line) == 1) { - return SMARTIRC_TYPE_MODECHANGE; - } else if (preg_match('/^:.*? QUIT :.*$/', $line) == 1) { - return SMARTIRC_TYPE_QUIT; - } else { - $this->log(SMARTIRC_DEBUG_MESSAGETYPES, 'DEBUG_MESSAGETYPES: SMARTIRC_TYPE_UNKNOWN!: "'.$line.'"', __FILE__, __LINE__); - return SMARTIRC_TYPE_UNKNOWN; - } - } - - /** - * updates the current connection state - * - * @return boolean - * @access private - */ - function _updatestate() - { - if (is_resource($this->_socket)) { - $rtype = get_resource_type($this->_socket); - if (($this->_socket !== false) && - ($rtype == 'socket' || $rtype == 'Socket' || $rtype == 'stream')) { - $this->_state = true; - return true; - } - } else { - $this->_state = false; - $this->_loggedin = false; - return false; - } - } - - /** - * returns the current connection state - * - * @return integer SMARTIRC_STATE_CONNECTED or SMARTIRC_STATE_DISCONNECTED - * @access private - */ - function _state() - { - $result = $this->_updatestate(); - - if ($result == true) { - return SMARTIRC_STATE_CONNECTED; - } else { - return SMARTIRC_STATE_DISCONNECTED; - } - } - - /** - * tries to find a messagehandler for the received message ($ircdata) and calls it - * - * @param string $messagecode - * @param object $ircdata - * @return void - * @access private - */ - function _handlemessage($messagecode, &$ircdata) - { - $found = false; - - if (is_numeric($messagecode)) { - if (!array_key_exists($messagecode, $this->nreplycodes)) { - $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: ignoring unrecognized messagecode! "'.$messagecode.'"', __FILE__, __LINE__); - $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: this IRC server ('.$this->_address.') doesn\'t conform to the RFC 2812!', __FILE__, __LINE__); - return; - } - - $methodname = 'event_'.strtolower($this->nreplycodes[$messagecode]); - $_methodname = '_'.$methodname; - $_codetype = 'by numeric'; - } else if (is_string($messagecode)) { // its not numericcode so already a name/string - $methodname = 'event_'.strtolower($messagecode); - $_methodname = '_'.$methodname; - $_codetype = 'by string'; - } - - // if exists call internal method for the handling - if (@method_exists($this, $_methodname)) { - $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: calling internal method "'.get_class($this).'->'.$_methodname.'" ('.$_codetype.')', __FILE__, __LINE__); - $this->$_methodname($ircdata); - $found = true; - } - - // if exist, call user defined method for the handling - if (@method_exists($this, $methodname)) { - $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: calling user defined method "'.get_class($this).'->'.$methodname.'" ('.$_codetype.')', __FILE__, __LINE__); - $this->$methodname($ircdata); - $found = true; - } - - if ($found == false) { - $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: no method found for "'.$messagecode.'" ('.$methodname.')', __FILE__, __LINE__); - } - } - - /** - * Strips control characters from a IRC message. - * - * @param string $text - * - * @return string - */ - function stripControlCharacters($text) { - $controlCodes = array( - '/(\x03(?:\d{1,2}(?:,\d{1,2})?)?)/', // Color code - '/\x02/', // Bold - '/\x0F/', // Escaped - '/\x16/', // Italic - '/\x1F/', // Underline - '/\x12/' - ); - return preg_replace($controlCodes,'',$text); - } - - /** - * tries to find a actionhandler for the received message ($ircdata) and calls it - * - * @param object $ircdata - * @return void - * @access private - */ - function _handleactionhandler(&$ircdata) - { - $handler = &$this->_actionhandler; - $handlercount = count($handler); - for ($i = 0; $i < $handlercount; $i++) { - $handlerobject = &$handler[$i]; - - if (substr($handlerobject->message, 0, 1) == '/') { - $regex = $handlerobject->message; - } else { - $regex = '/'.$handlerobject->message.'/'; - } - - $ircdata->message = $this->stripControlCharacters($ircdata->message); - if (($handlerobject->type & $ircdata->type) && - (preg_match($regex, $ircdata->message) == 1)) { - - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler match found for id: '.$i.' type: '.$ircdata->type.' message: "'.$ircdata->message.'" regex: "'.$regex.'"', __FILE__, __LINE__); - - $methodobject = &$handlerobject->object; - $method = $handlerobject->method; - - if (@method_exists($methodobject, $method)) { - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__); - $methodobject->$method($this, $ircdata); - } else { - $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: method doesn\'t exist! "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__); - } - } - } - } - - /** - * Delay reconnect - * - * @return void - * @access private - */ - function _delayReconnect() - { - if ($this->_reconnectdelay > 0) { - $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: delaying reconnect for '.$this->_reconnectdelay.' ms', __FILE__, __LINE__); - usleep($this->_reconnectdelay * 1000); - } - } - - /** - * getting current microtime, needed for benchmarks - * - * @return float - * @access private - */ - function _microint() - { - $tmp = microtime(); - $parts = explode(' ', $tmp); - $floattime = (float)$parts[0] + (float)$parts[1]; - return $floattime; - } - - /** - * adds an user to the channelobject or updates his info - * - * @param object $channel - * @param object $newuser - * @return void - * @access private - */ - function _adduser(&$channel, &$newuser) - { - $lowerednick = strtolower($newuser->nick); - if ($this->isJoined($channel->name, $newuser->nick)) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: updating user: '.$newuser->nick.' on channel: '.$channel->name, __FILE__, __LINE__); - - // lets update the existing user - $currentuser = &$channel->users[$lowerednick]; - - if ($newuser->ident !== null) { - $currentuser->ident = $newuser->ident; - } - if ($newuser->host !== null) { - $currentuser->host = $newuser->host; - } - if ($newuser->realname !== null) { - $currentuser->realname = $newuser->realname; - } - if ($newuser->ircop !== null) { - $currentuser->ircop = $newuser->ircop; - } - if ($newuser->founder !== null) { - $currentuser->founder = $newuser->founder; - } - if ($newuser->admin !== null) { - $currentuser->admin = $newuser->admin; - } - if ($newuser->op !== null) { - $currentuser->op = $newuser->op; - } - if ($newuser->hop !== null) { - $currentuser->hop = $newuser->hop; - } - if ($newuser->voice !== null) { - $currentuser->voice = $newuser->voice; - } - if ($newuser->away !== null) { - $currentuser->away = $newuser->away; - } - if ($newuser->server !== null) { - $currentuser->server = $newuser->server; - } - if ($newuser->hopcount !== null) { - $currentuser->hopcount = $newuser->hopcount; - } - } else { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding user: '.$newuser->nick.' to channel: '.$channel->name, __FILE__, __LINE__); - - // he is new just add the reference to him - $channel->users[$lowerednick] = &$newuser; - } - - $user = &$channel->users[$lowerednick]; - if ($user->founder) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding founder: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); - $channel->founders[$user->nick] = true; - } - if ($user->admin) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding admin: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); - $channel->admins[$user->nick] = true; - } - if ($user->op) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding op: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); - $channel->ops[$user->nick] = true; - } - if ($user->hop) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding half-op: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); - $channel->hops[$user->nick] = true; - } - if ($user->voice) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding voice: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); - $channel->voices[$user->nick] = true; - } - } - - /** - * removes an user from one channel or all if he quits - * - * @param object $ircdata - * @return void - * @access private - */ - function _removeuser(&$ircdata) - { - if ($ircdata->type & (SMARTIRC_TYPE_PART|SMARTIRC_TYPE_QUIT)) { - $nick = $ircdata->nick; - } else if ($ircdata->type & SMARTIRC_TYPE_KICK) { - $nick = $ircdata->rawmessageex[3]; - } else { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: unknown TYPE ('.$ircdata->type.') in _removeuser(), trying default', __FILE__, __LINE__); - $nick = $ircdata->nick; - } - - $lowerednick = strtolower($nick); - - if ($this->_nick == $nick) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: we left channel: '.$ircdata->channel.' destroying...', __FILE__, __LINE__); - unset($this->_channels[strtolower($ircdata->channel)]); - } else { - if ($ircdata->type & SMARTIRC_TYPE_QUIT) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: user '.$nick.' quit, removing him from all channels', __FILE__, __LINE__); - // remove the user from all channels - $channelkeys = array_keys($this->_channels); - foreach ($channelkeys as $channelkey) { - // loop through all channels - $channel = &$this->_channels[$channelkey]; - foreach ($channel->users as $uservalue) { - // loop through all user in this channel - if ($nick == $uservalue->nick) { - // found him - // kill him - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: found him on channel: '.$channel->name.' destroying...', __FILE__, __LINE__); - unset($channel->users[$lowerednick]); - - if (isset($channel->founders[$nick])) { - // die! - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from founder list', __FILE__, __LINE__); - unset($channel->founders[$nick]); - } - - if (isset($channel->admins[$nick])) { - // die! - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from admin list', __FILE__, __LINE__); - unset($channel->admins[$nick]); - } - - if (isset($channel->ops[$nick])) { - // die! - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from op list', __FILE__, __LINE__); - unset($channel->ops[$nick]); - } - - if (isset($channel->hops[$nick])) { - // die! - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from hop list', __FILE__, __LINE__); - unset($channel->hops[$nick]); - } - - if (isset($channel->voices[$nick])) { - // die!! - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from voice list', __FILE__, __LINE__); - unset($channel->voices[$nick]); - } - - // ups this was not DukeNukem 3D - } - } - } - } else { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing user: '.$nick.' from channel: '.$ircdata->channel, __FILE__, __LINE__); - $channel = &$this->_channels[strtolower($ircdata->channel)]; - unset($channel->users[$lowerednick]); - - if (isset($channel->founders[$nick])) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from founder list', __FILE__, __LINE__); - unset($channel->founders[$nick]); - } - - if (isset($channel->admins[$nick])) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from admin list', __FILE__, __LINE__); - unset($channel->admins[$nick]); - } - - if (isset($channel->ops[$nick])) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from op list', __FILE__, __LINE__); - unset($channel->ops[$nick]); - } - - if (isset($channel->hops[$nick])) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from hop list', __FILE__, __LINE__); - unset($channel->hops[$nick]); - } - - if (isset($channel->voices[$nick])) { - $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from voice list', __FILE__, __LINE__); - unset($channel->voices[$nick]); - } - } - } - } - - /** - * @return void - * @access private - */ - function _checkPHPVersion() - { - // doing nothing at the moment - } - - /** - * checks if the passed handlertype is valid - * - * @param integer $handlertype - * @return boolean - * @access private - */ - function _isValidType($handlertype) { - if ($handlertype & SMARTIRC_TYPE_ALL) { - return true; - } else { - return false; - } - } - - function _addIrcUser() - { - } - - function _updateIrcUser() - { - } - - function _removeIrcUser() - { - } - - function _addChannelUser() - { - } - - function _updateChannelUser() - { - } - - function _removeChannelUser() - { - } - - // - - function isError($object) - { - return (bool)(is_object($object) && (strtolower(get_class($object)) == 'net_smartirc_error')); - } - - function &throwError($message) - { - $error = new Net_SmartIRC_Error($message); - return $error; - } + /** + * @var resource + * @access private + */ + protected $_socket; + + /** + * @var string + * @access private + */ + protected $_address; + + /** + * @var integer + * @access private + */ + protected $_port; + + /** + * @var string + * @access private + */ + protected $_bindaddress = null; + + /** + * @var integer + * @access private + */ + protected $_bindport = 0; + + /** + * @var string + * @access private + */ + protected $_nick; + + /** + * @var string + * @access private + */ + protected $_username; + + /** + * @var string + * @access private + */ + protected $_realname; + + /** + * @var string + * @access private + */ + protected $_usermode; + + /** + * @var string + * @access private + */ + protected $_password; + + /** + * @var array + * @access private + */ + protected $_performs = array(); + + /** + * @var boolean + * @access private + */ + protected $_state = false; + + /** + * @var array + * @access private + */ + protected $_actionhandler = array(); + + /** + * @var array + * @access private + */ + protected $_timehandler = array(); + + /** + * @var integer + * @access private + */ + protected $_debug = SMARTIRC_DEBUG_NOTICE; + + /** + * @var array + * @access private + */ + protected $_messagebuffer = array(); + + /** + * @var integer + * @access private + */ + protected $_messagebuffersize; + + /** + * @var boolean + * @access private + */ + protected $_usesockets = false; + + /** + * @var integer + * @access private + */ + protected $_receivedelay = 100; + + /** + * @var integer + * @access private + */ + protected $_senddelay = 250; + + /** + * @var integer + * @access private + */ + protected $_logdestination = SMARTIRC_STDOUT; + + /** + * @var resource + * @access private + */ + protected $_logfilefp = 0; + + /** + * @var string + * @access private + */ + protected $_logfile = 'Net_SmartIRC.log'; + + /** + * @var integer + * @access private + */ + protected $_disconnecttime = 1000; + + /** + * @var boolean + * @access private + */ + protected $_loggedin = false; + + /** + * @var boolean + * @access private + */ + protected $_benchmark = false; + + /** + * @var integer + * @access private + */ + protected $_benchmark_starttime; + + /** + * @var integer + * @access private + */ + protected $_benchmark_stoptime; + + /** + * @var integer + * @access private + */ + protected $_actionhandlerid = 0; + + /** + * @var integer + * @access private + */ + protected $_timehandlerid = 0; + + /** + * @var array + * @access private + */ + protected $_motd = array(); + + /** + * @var array + * @access private + */ + protected $_channels = array(); + + /** + * @var boolean + * @access private + */ + protected $_channelsyncing = false; + + /** + * @var array + * @access private + */ + protected $_users = array(); + + /** + * @var boolean + * @access private + */ + protected $_usersyncing = false; + + /** + * Stores the path to the modules that can be loaded. + * + * @var string + * @access private + */ + protected $_modulepath = ''; + + /** + * Stores all objects of the modules. + * + * @var string + * @access private + */ + protected $_modules = array(); + + /** + * @var string + * @access private + */ + protected $_ctcpversion; + + /** + * @var mixed + * @access private + */ + protected $_mintimer = false; + + /** + * @var integer + * @access private + */ + protected $_maxtimer = 300000; + + /** + * @var integer + * @access private + */ + protected $_txtimeout = 300; + + /** + * @var integer + * @access private + */ + protected $_rxtimeout = 300; + + /** + * @var integer + * @access private + */ + protected $_selecttimeout; + + /** + * @var integer + * @access private + */ + protected $_lastrx; + + /** + * @var integer + * @access private + */ + protected $_lasttx; + + /** + * @var boolean + * @access private + */ + protected $_autoreconnect = false; + + /** + * @var integer + * @access private + */ + protected $_reconnectdelay = 10000; + + /** + * @var boolean + * @access private + */ + protected $_autoretry = false; + + /** + * @var integer + * @access private + */ + protected $_autoretrymax = 5; + + /** + * @var integer + * @access private + */ + protected $_autoretrycount = 0; + + /** + * @var boolean + * @access private + */ + protected $_connectionerror = false; + + /** + * @var boolean + * @access private + */ + protected $_runasdaemon = false; + + /** + * @var array + */ + protected $channelList = array(); + + /** + * All IRC replycodes, the index is the replycode name. + * + * @see $SMARTIRC_replycodes + * @var array + * @access public + */ + public $replycodes; + + /** + * All numeric IRC replycodes, the index is the numeric replycode. + * + * @see $SMARTIRC_nreplycodes + * @var array + * @access public + */ + public $nreplycodes; + + /** + * Stores all channels in this array where we are joined, works only if channelsyncing is activated. + * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc) + * $irc->channel['#test']->users['meebey']->nick; + * + * @see setChannelSyncing() + * @see Net_SmartIRC_channel + * @see Net_SmartIRC_channeluser + * @var array + * @access public + */ + public $channel; + + /** + * Stores all users that had/have contact with us (channel/query/notice etc.), works only if usersyncing is activated. + * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc) + * $irc->user['meebey']->host; + * + * @see setUserSyncing() + * @see Net_SmartIRC_ircuser + * @var array + * @access public + */ + public $user; + + /** + * Constructor. Initiates the messagebuffer and "links" the replycodes from + * global into properties. Also some PHP runtime settings are configured. + * + * @access public + */ + public function __construct() + { + ob_implicit_flush(true); + @set_time_limit(0); + $this->_messagebuffer[SMARTIRC_CRITICAL] = array(); + $this->_messagebuffer[SMARTIRC_HIGH] = array(); + $this->_messagebuffer[SMARTIRC_MEDIUM] = array(); + $this->_messagebuffer[SMARTIRC_LOW] = array(); + + $this->replycodes = &$GLOBALS['SMARTIRC_replycodes']; + $this->nreplycodes = &$GLOBALS['SMARTIRC_nreplycodes']; + + // hack till PHP allows (PHP5) $object->somemethod($param)->memberofobject + $this->channel = &$this->_channels; + // another hack + $this->user = &$this->_users; + + if (isset($_SERVER['REQUEST_METHOD'])) { + // the script is called from a browser, lets set default log destination + // to SMARTIRC_BROWSEROUT (makes browser friendly output) + $this->setLogdestination(SMARTIRC_BROWSEROUT); + } + } + + /** + * Enables/disables the usage of real sockets. + * + * Enables/disables the usage of real sockets instead of fsocks + * (works only if your PHP build has loaded the PHP socket extension) + * Default: false + * + * @param bool $boolean + * @return void + * @access public + */ + public function setUseSockets($boolean) + { + $this->_usesockets = false; + if ($boolean === true) { + if (@extension_loaded('sockets')) { + $this->_usesockets = true; + } else { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: your PHP build doesn\'t support real sockets, will use fsocks instead', __FILE__, __LINE__); + } + } + } + + /** + * Sets an IP address (and optionally, a port) to bind the socket to. + * + * Limits the bot to claiming only one of the machine's IPs as its home. + * Only works with setUseSockets(TRUE). Call with no parameters to unbind. + * + * @param string $addr + * @param int $port + * @return bool + * @access public + */ + public function setBindAddress($addr=null, $port=0) + { + if ($this->_usesockets) { + $this->_bindaddress = $addr; + $this->_bindport = $port; + } + return $this->_usesockets; + } + + /** + * Sets the level of debug messages. + * + * Sets the debug level (bitwise), useful for testing/developing your code. + * Here the list of all possible debug levels: + * SMARTIRC_DEBUG_NONE + * SMARTIRC_DEBUG_NOTICE + * SMARTIRC_DEBUG_CONNECTION + * SMARTIRC_DEBUG_SOCKET + * SMARTIRC_DEBUG_IRCMESSAGES + * SMARTIRC_DEBUG_MESSAGETYPES + * SMARTIRC_DEBUG_ACTIONHANDLER + * SMARTIRC_DEBUG_TIMEHANDLER + * SMARTIRC_DEBUG_MESSAGEHANDLER + * SMARTIRC_DEBUG_CHANNELSYNCING + * SMARTIRC_DEBUG_MODULES + * SMARTIRC_DEBUG_USERSYNCING + * SMARTIRC_DEBUG_ALL + * + * Default: SMARTIRC_DEBUG_NOTICE + * + * @see DOCUMENTATION + * @see SMARTIRC_DEBUG_NOTICE + * @param integer $level + * @return void + * @access public + */ + public function setDebug($level) + { + $this->_debug = $level; + } + + /** + * Enables/disables the benchmark engine. + * + * @param boolean $boolean + * @return void + * @access public + */ + public function setBenchmark($boolean) + { + if (is_bool($boolean)) { + $this->_benchmark = $boolean; + } else { + $this->_benchmark = false; + } + } + + /** + * Enables/disables channel syncing. + * + * Channel syncing means, all users on all channel we are joined are tracked in the + * channel array. This makes it very handy for botcoding. + * + * @param boolean $boolean + * @return void + * @access public + */ + public function setChannelSyncing($boolean) + { + if (is_bool($boolean)) { + $this->_channelsyncing = $boolean; + } else { + $this->_channelsyncing = false; + } + + if ($this->_channelsyncing == true) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: Channel syncing enabled', __FILE__, __LINE__); + } else { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: Channel syncing disabled', __FILE__, __LINE__); + } + } + + /** + * Enables/disables user syncing. + * + * User syncing means, all users we have or had contact with through channel, query or + * notice are tracked in the $irc->user array. This is very handy for botcoding. + * + * @param boolean $boolean + * @return void + * @access public + */ + public function setUserSyncing($boolean) + { + if (is_bool($boolean)) { + $this->_usersyncing = $boolean; + } else { + $this->_usersyncing = false; + } + + if ($this->_usersyncing == true) { + $this->log(SMARTIRC_DEBUG_USERSYNCING, 'DEBUG_USERSYNCING: User syncing enabled', __FILE__, __LINE__); + } else { + $this->log(SMARTIRC_DEBUG_USERSYNCING, 'DEBUG_USERSYNCING: User syncing disabled', __FILE__, __LINE__); + } + } + + /** + * Sets the CTCP version reply string. + * + * @param string $versionstring + * @return void + * @access public + */ + public function setCtcpVersion($versionstring) + { + $this->_ctcpversion = $versionstring; + } + + /** + * Sets the destination of all log messages. + * + * Sets the destination of log messages. + * $type can be: + * SMARTIRC_FILE for saving the log into a file + * SMARTIRC_STDOUT for echoing the log to stdout + * SMARTIRC_SYSLOG for sending the log to the syslog + * Default: SMARTIRC_STDOUT + * + * @see SMARTIRC_STDOUT + * @param integer $type must be on of the constants + * @return void + * @access public + */ + public function setLogdestination($type) + { + switch ($type) { + case SMARTIRC_FILE: + case SMARTIRC_STDOUT: + case SMARTIRC_SYSLOG: + case SMARTIRC_BROWSEROUT: + case SMARTIRC_NONE: + $this->_logdestination = $type; + break; + default: + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: unknown logdestination type ('.$type.'), will use STDOUT instead', __FILE__, __LINE__); + $this->_logdestination = SMARTIRC_STDOUT; + } + } + + /** + * Sets the file for the log if the destination is set to file. + * + * Sets the logfile, if {@link setLogdestination logdestination} is set to SMARTIRC_FILE. + * This should be only used with full path! + * + * @param string $file + * @return void + * @access public + */ + public function setLogfile($file) + { + $this->_logfile = $file; + } + + /** + * Sets the delaytime before closing the socket when disconnect. + * + * @param integer $milliseconds + * @return void + * @access public + */ + public function setDisconnecttime($milliseconds) + { + if (is_integer($milliseconds) && $milliseconds >= 100) { + $this->_disconnecttime = $milliseconds; + } else { + $this->_disconnecttime = 100; + } + } + + /** + * Sets the delaytime before attempting reconnect. + * Value of 0 disables the delay entirely. + * + * @param integer $milliseconds + * @return void + * @access public + */ + public function setReconnectdelay($milliseconds) + { + if (is_integer($milliseconds)) { + $this->_reconnectdelay = $milliseconds; + } else { + $this->_reconnectdelay = 10000; + } + } + + /** + * Sets the delay for receiving data from the IRC server. + * + * Sets the delaytime between messages that are received, this reduces your CPU load. + * Don't set this too low (min 100ms). + * Default: 100 + * + * @param integer $milliseconds + * @return void + * @access public + */ + public function setReceivedelay($milliseconds) + { + if (is_integer($milliseconds) && $milliseconds >= 100) { + $this->_receivedelay = $milliseconds; + } else { + $this->_receivedelay = 100; + } + } + + /** + * Sets the delay for sending data to the IRC server. + * + * Sets the delaytime between messages that are sent, because IRC servers doesn't like floods. + * This will avoid sending your messages too fast to the IRC server. + * Default: 250 + * + * @param integer $milliseconds + * @return void + * @access public + */ + public function setSenddelay($milliseconds) + { + if (is_integer($milliseconds)) { + $this->_senddelay = $milliseconds; + } else { + $this->_senddelay = 250; + } + } + + /** + * Enables/disables autoreconnecting. + * + * @param boolean $boolean + * @return void + * @access public + */ + public function setAutoReconnect($boolean) + { + if (is_bool($boolean)) { + $this->_autoreconnect = $boolean; + } else { + $this->_autoreconnect = false; + } + } + + /** + * Enables/disables autoretry for connecting to a server. + * + * @param boolean $boolean + * @return void + * @access public + */ + public function setAutoRetry($boolean) + { + if (is_bool($boolean)) { + $this->_autoretry = $boolean; + } else { + $this->_autoretry = false; + } + } + + /** + * Sets the maximum number of attempts to connect to a server + * before giving up. + * + * @param integer $autoretrymax + * @return void + * @access public + */ + public function setAutoRetryMax($autoretrymax) + { + if (is_integer($autoretrymax)) { + $this->_autoretrymax = $autoretrymax; + } else { + $this->_autoretrymax = 5; + } + } + + /** + * Sets the receive timeout. + * + * If the timeout occurs, the connection will be reinitialized + * Default: 300 seconds + * + * @param integer $seconds + * @return void + * @access public + */ + public function setReceiveTimeout($seconds) + { + if (is_integer($seconds)) { + $this->_rxtimeout = $seconds; + } else { + $this->_rxtimeout = 300; + } + } + + /** + * Sets the transmit timeout. + * + * If the timeout occurs, the connection will be reinitialized + * Default: 300 seconds + * + * @param integer $seconds + * @return void + * @access public + */ + public function setTransmitTimeout($seconds) + { + if (is_integer($seconds)) { + $this->_txtimeout = $seconds; + } else { + $this->_txtimeout = 300; + } + } + + /** + * Sets the paths for the modules. + * + * @param integer $path + * @return void + * @access public + */ + public function setModulepath($path) + { + $this->_modulepath = $path; + } + + /** + * Sets wheter the script should be run as a daemon or not + * ( actually disables/enables ignore_user_abort() ) + * + * @param boolean $boolean + * @return void + * @access public + */ + public function setRunAsDaemon($boolean) + { + if ($boolean === true) { + $this->_runasdaemon = true; + ignore_user_abort(true); + set_time_limit(0); + } else { + $this->_runasdaemon = false; + } + } + + /** + * Starts the benchmark (sets the counters). + * + * @return void + * @access public + */ + public function startBenchmark() + { + $this->_benchmark_starttime = $this->_microint(); + $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark started', __FILE__, __LINE__); + } + + /** + * Stops the benchmark and displays the result. + * + * @return void + * @access public + */ + public function stopBenchmark() + { + $this->_benchmark_stoptime = $this->_microint(); + $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark stopped', __FILE__, __LINE__); + + if ($this->_benchmark) { + $this->showBenchmark(); + } + } + + /** + * Shows the benchmark result. + * + * @return void + * @access public + */ + public function showBenchmark() + { + $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark time: '.((float)$this->_benchmark_stoptime-(float)$this->_benchmark_starttime), __FILE__, __LINE__); + } + + /** + * Adds an entry to the log. + * + * Adds an entry to the log with Linux style log format. + * Possible $level constants (can also be combined with "|"s) + * SMARTIRC_DEBUG_NONE + * SMARTIRC_DEBUG_NOTICE + * SMARTIRC_DEBUG_CONNECTION + * SMARTIRC_DEBUG_SOCKET + * SMARTIRC_DEBUG_IRCMESSAGES + * SMARTIRC_DEBUG_MESSAGETYPES + * SMARTIRC_DEBUG_ACTIONHANDLER + * SMARTIRC_DEBUG_TIMEHANDLER + * SMARTIRC_DEBUG_MESSAGEHANDLER + * SMARTIRC_DEBUG_CHANNELSYNCING + * SMARTIRC_DEBUG_MODULES + * SMARTIRC_DEBUG_USERSYNCING + * SMARTIRC_DEBUG_ALL + * + * @see SMARTIRC_DEBUG_NOTICE + * @param integer $level bit constants (SMARTIRC_DEBUG_*) + * @param string $file + * @param string $entry the new log entry + * @param string $line + * @return void + * @access protected + */ + protected function log($level, $entry, $file = null, $line = null) + { + // prechecks + if (!(is_integer($level)) || + !($level & SMARTIRC_DEBUG_ALL)) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: invalid log level passed to log() ('.$level.')', __FILE__, __LINE__); + return; + } + + if (!($level & $this->_debug) || + ($this->_logdestination == SMARTIRC_NONE)) { + return; + } + + if (substr($entry, -1) != "\n") { + $entry .= "\n"; + } + + if ($file !== null && + $line !== null) { + $file = basename($file); + $entry = $file.'('.$line.') '.$entry; + } else { + $entry = 'unknown(0) '.$entry; + } + + $formatedentry = date('M d H:i:s ').$entry; + switch ($this->_logdestination) { + case SMARTIRC_STDOUT: + echo $formatedentry; + flush(); + break; + case SMARTIRC_BROWSEROUT: + echo '
'.htmlentities($formatedentry).'
'; + break; + case SMARTIRC_FILE: + if (!is_resource($this->_logfilefp)) { + if ($this->_logfilefp === null) { + // we reconncted and don't want to destroy the old log entries + $this->_logfilefp = fopen($this->_logfile,'a'); + } else { + $this->_logfilefp = fopen($this->_logfile,'w'); + } + } + fwrite($this->_logfilefp, $formatedentry); + fflush($this->_logfilefp); + break; + case SMARTIRC_SYSLOG: + if (!is_int($this->_logfilefp)) { + $this->_logfilefp = openlog('Net_SmartIRC', LOG_NDELAY, LOG_DAEMON); + } + syslog(LOG_INFO, $entry); + break; + } + } + + /** + * Returns the full motd. + * + * @return array + * @access public + */ + public function getMotd() + { + return $this->_motd; + } + + /** + * Returns the usermode. + * + * @return string + * @access public + */ + public function getUsermode() + { + return $this->_usermode; + } + + /** + * Returns a reference to the channel object of the specified channelname. + * + * @param string $channelname + * @return object + * @access public + */ + public function getChannel($channelname) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: getChannel() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($this->isJoined($channelname)) { + return $this->_channels[strtolower($channelname)]; + } else { + return false; + } + } + + /** + * Returns a reference to the user object for the specified username and channelname. + * + * @param string $channelname + * @param string $username + * @return object + * @access public + */ + public function getUser($channelname, $username) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: getUser() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($this->isJoined($channelname, $username)) { + return $this->_channels[strtolower($channelname)]->users[strtolower($username)]; + } else { + return false; + } + } + + /** + * Creates the sockets and connects to the IRC server on the given port. + * + * @param string $address + * @param integer $port + * @return boolean + * @access public + */ + public function connect($address, $port) + { + $this->_address = $address; + $this->_port = $port; + $this->_autoretrycount = 0; + $connected = false; + if ($this->_autoretry === true && ($this->_autoretrycount < $this->_autoretrymax)) { + while ($this->_autoretrycount < $this->_autoretrymax) { + $connected = $this->connectHelper($address, $port); + if ($connected === true) { + break; + } else { + $this->_delayReconnect(); + $this->_autoretrycount++; + } + } + } else { + $connected = $this->connectHelper($address, $port); + } + if ($connected === false) { + $this->_connectionerror = true; + } + return $connected; + } + + /** + * Helper method for connecting. + * + * @return boolean + * @access protected + */ + protected function connectHelper() + { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connecting', __FILE__, __LINE__); + $errno = $errstr = 0; + + if ($this->_usesockets == true) { + $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: using real sockets', __FILE__, __LINE__); + $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($this->_bindaddress !== null) { + if (socket_bind($this->_socket, $this->_bindaddress, $this->_bindport)) { + $this->log(SMARTIRC_DEBUG_SOCKET, + 'DEBUG_SOCKET: bound to '.$this->_bindaddress.':' + .$this->_bindport, __FILE__, __LINE__); + } else { + $errno = socket_last_error($this->_socket); + + $error_msg = + 'ERROR: Unable to bind '.$this->_bindaddress.':' + .$this->_bindport.' reason: '.socket_strerror($errno) + .' ('.$errno.')'; + + $this->log(SMARTIRC_DEBUG_NOTICE, 'Warning: '.$error_msg, __FILE__, __LINE__); + echo $error_msg . PHP_EOL; + return false; + } + } + $result = @socket_connect($this->_socket, $this->_address, $this->_port); + } else { + $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: using fsockets', __FILE__, __LINE__); + $result = fsockopen($this->_address, $this->_port, $errno, $errstr); + } + + if ($result === false) { + if ($this->_usesockets == true) { + $error = socket_strerror(socket_last_error($this->_socket)); + } else { + $error = $errstr.' ('.$errno.')'; + } + + $error_msg = 'couldn\'t connect to "'.$this->_address.'" reason: "'.$error.'"'; + $this->log(SMARTIRC_DEBUG_NOTICE, 'Warning: '.$error_msg, __FILE__, __LINE__); + + if (($this->_autoretry == true) && + ($this->_autoretrycount < $this->_autoretrymax)) { + echo 'ERROR connecting to (' . $this->_address . ':' . $this->_port . + ') error: (' . $error . ') retry (' . $this->_autoretrycount . + '/' . $this->_autoretrymax . + '). Sleeping for (' . $this->_reconnectdelay . ') ms.' . PHP_EOL; + return false; + } else { + echo 'ERROR connecting to (' . $this->_address . ':' . $this->_port . + ') after (' . $this->_autoretrymax . ') retries, error: (' . + $error . ').' . PHP_EOL; + return false; + } + } else { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connected', __FILE__, __LINE__); + $this->_autoretrycount = 0; + $this->_connectionerror = false; + + if ($this->_usesockets != true) { + $this->_socket = $result; + $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: activating nonblocking fsocket mode', __FILE__, __LINE__); + stream_set_blocking($this->_socket, 0); + } + } + + $this->_lastrx = $this->_lasttx = time(); + $this->_updatestate(); + + return $result; + } + + /** + * Disconnects from the IRC server nicely with a QUIT or just destroys the socket. + * + * Disconnects from the IRC server in the given quickness mode. + * $quickdisconnect: + * true, just close the socket + * false, send QUIT and wait {@link $_disconnectime $_disconnectime} before closing the socket + * + * @param boolean $quickdisconnect default: false + * @return boolean + * @access public + */ + public function disconnect($quickdisconnect = false) + { + if ($this->_connectionerror === false && $this->_state() == SMARTIRC_STATE_CONNECTED) { + if ($quickdisconnect == false) { + $this->_send('QUIT', SMARTIRC_CRITICAL); + usleep($this->_disconnecttime*1000); + } + + if ($this->_usesockets == true) { + @socket_shutdown($this->_socket); + @socket_close($this->_socket); + } else { + fclose($this->_socket); + } + + $this->_updatestate(); + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: disconnected', __FILE__, __LINE__); + } + + if ($this->_channelsyncing == true) { + // let's clean our channel array + $this->_channels = array(); + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: cleaned channel array', __FILE__, __LINE__); + } + + if ($this->_usersyncing == true) { + // let's clean our user array + $this->_users = array(); + $this->log(SMARTIRC_DEBUG_USERSYNCING, 'DEBUG_USERSYNCING: cleaned user array', __FILE__, __LINE__); + } + + if ($this->_logdestination == SMARTIRC_FILE) { + fclose($this->_logfilefp); + $this->_logfilefp = null; + } else if ($this->_logdestination == SMARTIRC_SYSLOG) { + closelog(); + } + + return true; + } + + /** + * Reconnects to the IRC server with the same login info, + * it also rejoins the channels + * + * @return void + * @access public + */ + public function reconnect() + { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: reconnecting...', __FILE__, __LINE__); + $this->disconnect(true); + $this->connect($this->_address, $this->_port); + $this->login($this->_nick, $this->_realname, $this->_usermode, $this->_username, $this->_password); + $this->joinChannels($this->channelList); + } + + /** + * Join one or more channel. + * + * @param array $channelarray array('#channelname1' => 'password', '#channelname2' => null); + * @param int $priority + * + * @return bool + */ + public function joinChannels($channelarray, $priority = SMARTIRC_MEDIUM) + { + if ($this->_connectionerror === true || $this->_state() === SMARTIRC_STATE_DISCONNECTED) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'Warning: you must connect to IRC before joining channels!', __FILE__, __LINE__); + return false; + } + + $this->channelList = $channelarray; + return $this->join($channelarray, $priority); + } + + /** + * login and register nickname on the IRC network + * + * Registers the nickname and user information on the IRC network. + * + * @param string $nick + * @param string $realname + * @param integer $usermode + * @param string $username + * @param string $password + * @return bool + * @access public + */ + public function login($nick, $realname, $usermode = 0, $username = null, $password = null) + { + if ($this->_connectionerror === true || $this->_state() === SMARTIRC_STATE_DISCONNECTED) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'Warning: you must connect to IRC before logging in!', __FILE__, __LINE__); + return false; + } + + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: logging in', __FILE__, __LINE__); + + $this->_nick = str_replace(' ', '', $nick); + $this->_realname = $realname; + + if ($username !== null) { + $this->_username = str_replace(' ', '', $username); + } else { + $this->_username = str_replace(' ', '', exec('whoami')); + } + + if ($password !== null) { + $this->_password = $password; + $this->_send('PASS '.$this->_password, SMARTIRC_CRITICAL); + } + + if (!is_numeric($usermode)) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'Warning: login() usermode ('.$usermode.') is not valid, will use 0 instead', __FILE__, __LINE__); + $usermode = 0; + } + $this->_usermode = $usermode; + + $this->_send('NICK '.$this->_nick, SMARTIRC_CRITICAL); + $this->_send('USER '.$this->_username.' '.$this->_usermode.' '.SMARTIRC_UNUSED.' :'.$this->_realname, SMARTIRC_CRITICAL); + + if (count($this->_performs)) { + // if we have extra commands to send, do it now + foreach($this->_performs as $command) { + $this->_send($command, SMARTIRC_HIGH); + } + // if we sent "ns auth" commands, we may need to resend our nick + $this->_send('NICK '.$this->_nick, SMARTIRC_HIGH); + } + return true; + } + + // + + /** + * adds a command to the list of commands to be sent after login() info + * + * @param string $cmd the command to add to the perform list + * @access public + */ + public function perform($cmd) + { + $this->_performs[] = $cmd; + } + + /** + * checks if the passed nickname is our own nickname + * + * @param string $nickname + * @return boolean + * @access public + */ + public function isMe($nickname) + { + if ($nickname == $this->_nick) { + return true; + } else { + return false; + } + } + + /** + * checks if we or the given user is joined to the specified channel and returns the result + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $nickname + * @return boolean + * @access public + */ + public function isJoined($channel, $nickname = null) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'Warning: isJoined() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($nickname === null) { + $nickname = $this->_nick; + } + + if (isset($this->_channels[strtolower($channel)]->users[strtolower($nickname)])) { + return true; + } + + return false; + } + + /** + * Checks if we or the given user is founder on the specified channel and returns the result. + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $nickname + * @return boolean + * @access public + */ + public function isFounder($channel, $nickname = null) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isFounder() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($nickname === null) { + $nickname = $this->_nick; + } + + if ($this->isJoined($channel, $nickname)) { + if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->founder) { + return true; + } + } + + return false; + } + + /** + * Checks if we or the given user is admin on the specified channel and returns the result. + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $nickname + * @return boolean + * @access public + */ + public function isAdmin($channel, $nickname = null) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isAdmin() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($nickname === null) { + $nickname = $this->_nick; + } + + if ($this->isJoined($channel, $nickname)) { + if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->admin) { + return true; + } + } + + return false; + } + + /** + * Checks if we or the given user is opped on the specified channel and returns the result. + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $nickname + * @return boolean + * @access public + */ + public function isOpped($channel, $nickname = null) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isOpped() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($nickname === null) { + $nickname = $this->_nick; + } + + if ($this->isJoined($channel, $nickname)) { + if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->op) { + return true; + } + } + + return false; + } + + /** + * Checks if we or the given user is hopped on the specified channel and returns the result. + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $nickname + * @return boolean + * @access public + */ + public function isHopped($channel, $nickname = null) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isHopped() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($nickname === null) { + $nickname = $this->_nick; + } + + if ($this->isJoined($channel, $nickname)) { + if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->hop) { + return true; + } + } + + return false; + } + + /** + * Checks if we or the given user is voiced on the specified channel and returns the result. + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $nickname + * @return boolean + * @access public + */ + public function isVoiced($channel, $nickname = null) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isVoiced() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($nickname === null) { + $nickname = $this->_nick; + } + + if ($this->isJoined($channel, $nickname)) { + if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->voice) { + return true; + } + } + + return false; + } + + /** + * Checks if the hostmask is on the specified channel banned and returns the result. + * ChannelSyncing is required for this. + * + * @see setChannelSyncing + * @param string $channel + * @param string $hostmask + * @return boolean + * @access public + */ + public function isBanned($channel, $hostmask) + { + if ($this->_channelsyncing != true) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isBanned() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__); + return false; + } + + if ($this->isJoined($channel)) { + $result = array_search($hostmask, $this->_channels[strtolower($channel)]->bans); + + if ($result !== false) { + return true; + } + } + + return false; + } + + /** + * goes into receive mode + * + * Goes into receive and idle mode. Only call this if you want to "spawn" the bot. + * No further lines of PHP code will be processed after this call, only the bot methods! + * + * @return boolean + * @access public + */ + public function listen() + { + while (true) { + if ($this->listenOnce() === false) { + break; + } + } + + return false; + } + + /** + * goes into receive mode _only_ for one pass + * + * Goes into receive mode. It will return when one pass is complete. + * Use this when you want to connect to multiple IRC servers. + * + * @return boolean + * @access public + */ + public function listenOnce() + { + if ($this->checkConnection()) { + $this->_rawreceive(); + if ($this->checkConnection()) { + return true; + } + } + return false; + } + + /** + * Check if the connection is still up. + * + * @return bool + */ + protected function checkConnection() + { + if ($this->_connectionerror || $this->_state() === SMARTIRC_STATE_DISCONNECTED) { + if ($this->_autoreconnect) { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connection error detected, will reconnect!', __FILE__, __LINE__); + $this->reconnect(); + return ($this->_connectionerror && $this->_state() === SMARTIRC_STATE_DISCONNECTED); + } else { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connection error detected, will disconnect!', __FILE__, __LINE__); + $this->disconnect(); + return false; + } + } + return true; + } + + /** + * waits for a special message type and puts the answer in $result + * + * Creates a special actionhandler for that given TYPE and returns the answer. + * This will only receive the requested type, immediately quit and disconnect from the IRC server. + * Made for showing IRC statistics on your homepage, or other IRC related information. + * + * @param integer $messagetype see in the documentation 'Message Types' + * @return array answer from the IRC server for this $messagetype + * @access public + */ + public function listenFor($messagetype) + { + $listenfor = new Net_SmartIRC_listenfor(); + $this->registerActionhandler($messagetype, '.*', $listenfor, 'handler'); + $this->listen(); + $result = $listenfor->result; + + if (isset($listenfor)) { + unset($listenfor); + } + + return $result; + } + + /** + * registers a new actionhandler and returns the assigned id + * + * Registers an actionhandler in Net_SmartIRC for calling it later. + * The actionhandler id is needed for unregistering the actionhandler. + * + * @see example.php + * @param integer $handlertype bits constants, see in this documentation Message Types + * @param string $regexhandler the message that has to be in the IRC message in regex syntax + * @param object $object a reference to the objects of the method + * @param string $methodname the methodname that will be called when the handler happens + * @return integer assigned actionhandler id + * @access public + */ + public function registerActionhandler($handlertype, $regexhandler, &$object, $methodname) + { + // precheck + if (!$this->_isValidType($handlertype)) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: passed invalid handlertype to registerActionhandler()', __FILE__, __LINE__); + return false; + } + + $id = $this->_actionhandlerid++; + $newactionhandler = new Net_SmartIRC_actionhandler(); + + $newactionhandler->id = $id; + $newactionhandler->type = $handlertype; + $newactionhandler->message = $regexhandler; + $newactionhandler->object = &$object; + $newactionhandler->method = $methodname; + + $this->_actionhandler[] = &$newactionhandler; + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') registered', __FILE__, __LINE__); + return $id; + } + + /** + * unregisters an existing actionhandler + * + * @param integer $handlertype + * @param string $regexhandler + * @param object $object + * @param string $methodname + * @return boolean + * @access public + */ + public function unregisterActionhandler($handlertype, $regexhandler, &$object, $methodname) + { + // precheck + if (!$this->_isValidType($handlertype)) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: passed invalid handlertype to unregisterActionhandler()', __FILE__, __LINE__); + return false; + } + + $handler = &$this->_actionhandler; + $handlercount = count($handler); + + for ($i = 0; $i < $handlercount; $i++) { + $handlerobject = &$handler[$i]; + + if ($handlerobject->type == $handlertype && + $handlerobject->message == $regexhandler && + $handlerobject->method == $methodname) { + + $id = $handlerobject->id; + + if (isset($this->_actionhandler[$i])) { + unset($this->_actionhandler[$i]); + } + + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered', __FILE__, __LINE__); + $this->_reorderactionhandler(); + return true; + } + } + + $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__); + return false; + } + + /** + * unregisters an existing actionhandler via the id + * + * @param integer $id + * @return boolean + * @access public + */ + public function unregisterActionid($id) + { + $handler = &$this->_actionhandler; + $handlercount = count($handler); + for ($i = 0; $i < $handlercount; $i++) { + $handlerobject = &$handler[$i]; + + if ($handlerobject->id == $id) { + if (isset($this->_actionhandler[$i])) { + unset($this->_actionhandler[$i]); + } + + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered', __FILE__, __LINE__); + $this->_reorderactionhandler(); + return true; + } + } + + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: could not find actionhandler id: '.$id.' _not_ unregistered', __FILE__, __LINE__); + return false; + } + + /** + * registers a timehandler and returns the assigned id + * + * Registers a timehandler in Net_SmartIRC, which will be called in the specified interval. + * The timehandler id is needed for unregistering the timehandler. + * + * @see example7.php + * @param integer $interval interval time in milliseconds + * @param object $object a reference to the objects of the method + * @param string $methodname the methodname that will be called when the handler happens + * @return integer assigned timehandler id + * @access public + */ + public function registerTimehandler($interval, &$object, $methodname) + { + $id = $this->_timehandlerid++; + $newtimehandler = new Net_SmartIRC_timehandler(); + + $newtimehandler->id = $id; + $newtimehandler->interval = $interval; + $newtimehandler->object = &$object; + $newtimehandler->method = $methodname; + $newtimehandler->lastmicrotimestamp = $this->_microint(); + + $this->_timehandler[] = &$newtimehandler; + $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: timehandler('.$id.') registered', __FILE__, __LINE__); + + if (($interval < $this->_mintimer) || ($this->_mintimer == false)) { + $this->_mintimer = $interval; + } + + return $id; + } + + /** + * unregisters an existing timehandler via the id + * + * @see example7.php + * @param integer $id + * @return boolean + * @access public + */ + public function unregisterTimeid($id) + { + $handler = &$this->_timehandler; + $handlercount = count($handler); + for ($i = 0; $i < $handlercount; $i++) { + $handlerobject = &$handler[$i]; + + if ($handlerobject->id == $id) { + if (isset($this->_timehandler[$i])) { + unset($this->_timehandler[$i]); + } + + $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: timehandler('.$id.') unregistered', __FILE__, __LINE__); + $this->_reordertimehandler(); + $this->_updatemintimer(); + return true; + } + } + + $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: could not find timehandler id: '.$id.' _not_ unregistered', __FILE__, __LINE__); + return false; + } + + public function loadModule($name) + { + // is the module already loaded? + if (in_array($name, $this->_modules)) { + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING! module with the name "'.$name.'" already loaded!', __FILE__, __LINE__); + return false; + } + + $filename = $this->_modulepath.'/'.$name.'.php'; + if (!file_exists($filename)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: couldn\'t load module "'.$filename.'" file doesn\'t exist', __FILE__, __LINE__); + return false; + } + + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: loading module: "'.$name.'"...', __FILE__, __LINE__); + // pray that there is no parse error, it will kill us! + include_once($filename); + $classname = 'Net_SmartIRC_module_'.$name; + + if (!class_exists($classname)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: class '.$classname.' not found in '.$filename, __FILE__, __LINE__); + return false; + } + + $methods = get_class_methods($classname); + if (!in_array('__construct', $methods) && !in_array('module_init', $methods)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required method'.$classname.'::__construct not found, aborting...', __FILE__, __LINE__); + return false; + } + + if (!in_array('__destruct', $methods) && !in_array('module_exit', $methods)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required method'.$classname.'::__destruct not found, aborting...', __FILE__, __LINE__); + return false; + } + + $vars = array_keys(get_class_vars($classname)); + if (!in_array('name', $vars)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::name not found, aborting...', __FILE__, __LINE__); + return false; + } + + if (!in_array('description', $vars)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::description not found, aborting...', __FILE__, __LINE__); + return false; + } + + if (!in_array('author', $vars)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::author not found, aborting...', __FILE__, __LINE__); + return false; + } + + if (!in_array('license', $vars)) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: required variable '.$classname.'::license not found, aborting...', __FILE__, __LINE__); + return false; + } + + // looks like the module satisfies us, so instantiate it + if (in_array('module_init', $methods)) { + // we're using an old module_init style module + $module = new $classname; + } else if (func_num_args() == 1) { + // we're using a new __construct style module, which maintains its + // own reference to the $irc client object it's being used on + $module = new $classname($this); + } else { + // we're using new style AND we have args to pass to the constructor + if (func_num_args() == 2) { + // only one arg, so pass it as is + $module = new $classname($this, func_get_arg(1)); + } else { + // multiple args, so pass them in an array + $module = new $classname($this, array_slice(func_get_args(), 1)); + } + } + + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: successfully created' + .' instance of: '.$classname, __FILE__, __LINE__ + ); + + // check for deprecated init function and run it if it exists + if (in_array('module_init', get_class_methods($classname))) { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: calling ' + .$classname.'::module_init()', __FILE__, __LINE__ + ); + $module->module_init($this); + } + + $this->_modules[$name] = &$module; + + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: successfully loaded' + .' module: '.$name, __FILE__, __LINE__ + ); + return true; + } + + public function unloadModule($name) + { + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: unloading module: '.$name.'...', __FILE__, __LINE__); + + $modules_keys = array_keys($this->_modules); + $modulecount = count($modules_keys); + for ($i = 0; $i < $modulecount; $i++) { + $module = &$this->_modules[$modules_keys[$i]]; + $modulename = strtolower(get_class($module)); + + if ($modulename == 'net_smartirc_module_'.$name) { + if (in_array('module_exit', get_class_methods($modulename))) { + $module->module_exit($this); + } + unset($this->_modules[$i]); // should call __destruct() on it + $this->_reordermodules(); + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: successfully' + .' unloaded module: '.$name, __FILE__, __LINE__); + return true; + } + } + + $this->log(SMARTIRC_DEBUG_MODULES, 'DEBUG_MODULES: couldn\'t unload' + .' module: '.$name.' (it\'s not loaded!)', __FILE__, __LINE__ + ); + return false; + } + + /** + * sends an IRC message + * + * Adds a message to the messagequeue, with the optional priority. + * $priority: + * SMARTIRC_CRITICAL + * SMARTIRC_HIGH + * SMARTIRC_MEDIUM + * SMARTIRC_LOW + * + * @param string $data + * @param integer $priority must be one of the priority constants + * @return boolean + * @access public + */ + public function send($data, $priority = SMARTIRC_MEDIUM) + { + return $this->_send($data, $priority); + } + + // + /** + * changes a already used nickname to a new nickname plus 3 random digits + * + * @return void + * @access private + */ + protected function _nicknameinuse() + { + $newnickname = substr($this->_nick, 0, 5).rand(0, 999); + $this->changeNick($newnickname, SMARTIRC_CRITICAL); + } + + /** + * sends an IRC message + * + * Adds a message to the messagequeue, with the optional priority. + * $priority: + * SMARTIRC_CRITICAL + * SMARTIRC_HIGH + * SMARTIRC_MEDIUM + * SMARTIRC_LOW + * + * @param string $data + * @param integer $priority must be one of the priority constants + * @return boolean + * @access private + */ + protected function _send($data, $priority = SMARTIRC_MEDIUM) + { + switch ($priority) { + case SMARTIRC_CRITICAL: + $this->_rawsend($data); + break; + case SMARTIRC_HIGH: + case SMARTIRC_MEDIUM: + case SMARTIRC_LOW: + $this->_messagebuffer[$priority][] = $data; + break; + default: + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: message ('.$data.') with an invalid priority passed ('.$priority.'), message is ignored!', __FILE__, __LINE__); + return false; + } + + return true; + } + + /** + * checks the buffer if there are messages to send + * + * @return void + * @access private + */ + protected function _checkbuffer() + { + if (!$this->_loggedin) { + return; + } + + static $highsent = 0; + static $lastmicrotimestamp = 0; + + if ($lastmicrotimestamp == 0) { + $lastmicrotimestamp = $this->_microint(); + } + + $highcount = count($this->_messagebuffer[SMARTIRC_HIGH]); + $mediumcount = count($this->_messagebuffer[SMARTIRC_MEDIUM]); + $lowcount = count($this->_messagebuffer[SMARTIRC_LOW]); + $this->_messagebuffersize = $highcount+$mediumcount+$lowcount; + + // don't send them too fast + if ($this->_microint() >= ($lastmicrotimestamp+($this->_senddelay/1000))) { + $result = null; + if ($highcount > 0 && $highsent <= 2) { + $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_HIGH])); + $lastmicrotimestamp = $this->_microint(); + $highsent++; + } else if ($mediumcount > 0) { + $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_MEDIUM])); + $lastmicrotimestamp = $this->_microint(); + $highsent = 0; + } else if ($lowcount > 0) { + $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_LOW])); + $lastmicrotimestamp = $this->_microint(); + } + } + } + + /** + * Checks the running timers and calls the registered timehandler, + * when the interval is reached. + * + * @return void + * @access private + */ + protected function _checktimer() + { + if (!$this->_loggedin) { + return; + } + + // has to be count() because the array may change during the loop! + for ($i = 0; $i < count($this->_timehandler); $i++) { + $handlerobject = &$this->_timehandler[$i]; + $microtimestamp = $this->_microint(); + if ($microtimestamp >= ($handlerobject->lastmicrotimestamp+($handlerobject->interval/1000))) { + $methodobject = &$handlerobject->object; + $method = $handlerobject->method; + $handlerobject->lastmicrotimestamp = $microtimestamp; + + if (@method_exists($methodobject, $method)) { + $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__); + $methodobject->$method($this); + } + } + } + } + + /** + * Checks if a receive or transmit timeout occured and reconnects if configured + * + * @return void + * @access private + */ + protected function _checktimeout() + { + if ($this->_autoreconnect == true) { + $timestamp = time(); + if ($this->_lastrx < ($timestamp - $this->_rxtimeout)) { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: receive timeout detected, doing reconnect...', __FILE__, __LINE__); + $this->_delayReconnect(); + $this->reconnect(); + } else if ($this->_lasttx < ($timestamp - $this->_txtimeout)) { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: transmit timeout detected, doing reconnect...', __FILE__, __LINE__); + $this->_delayReconnect(); + $this->reconnect(); + } + } + } + + /** + * sends a raw message to the IRC server (don't use this!!) + * + * Use message() or send() instead. + * + * @param string $data + * @return boolean + * @access private + */ + protected function _rawsend($data) + { + if ($this->_state() == SMARTIRC_STATE_CONNECTED) { + $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: sent: "'.$data.'"', __FILE__, __LINE__); + + if ($this->_usesockets == true) { + $result = socket_write($this->_socket, $data.SMARTIRC_CRLF); + } else { + $result = fwrite($this->_socket, $data.SMARTIRC_CRLF); + } + + + if ($result === false) { + // writing to the socket failed, means the connection is broken + $this->_connectionerror = true; + + return false; + } else { + $this->_lasttx = time(); + return true; + } + } else { + return false; + } + } + + /** + * goes into main receive mode _once_ per call and waits for messages from the IRC server + * + * @return bool + * @access private + */ + protected function _rawreceive() + { + $lastpart = ''; + $rawdataar = array(); + + $this->_checkbuffer(); + + $timeout = $this->_selecttimeout(); + if ($this->_usesockets == true) { + $sread = array($this->_socket); + // this will trigger a warning when catching a signal + $result = @socket_select($sread, $w = null, $e = null, 0, $timeout*1000); + + if ($result == 1) { + // the socket got data to read + $rawdata = socket_read($this->_socket, 10240); + } else if ($result === false) { + if (socket_last_error() == 4) { + // we got hit with a SIGHUP signal + $rawdata = null; + global $bot; + + if (is_callable(array($bot, 'reload'))) { + $bot->reload(); + } + } else { + // panic! panic! something went wrong! + $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket_select() returned false, something went wrong! Reason: '.socket_strerror(socket_last_error()), __FILE__, __LINE__); + exit; + } + } else { + // no data + $rawdata = null; + } + } else { + usleep($this->_receivedelay*1000); + $rawdata = fread($this->_socket, 10240); + } + if ($rawdata === false) { + // reading from the socket failed, the connection is broken + $this->_connectionerror = true; + return false; + } + + $this->_checktimer(); + $this->_checktimeout(); + + if ($rawdata !== null && !empty($rawdata)) { + $this->_lastrx = time(); + $rawdata = str_replace("\r", '', $rawdata); + $rawdata = $lastpart.$rawdata; + + $lastpart = substr($rawdata, strrpos($rawdata ,"\n")+1); + $rawdata = substr($rawdata, 0, strrpos($rawdata ,"\n")); + $rawdataar = explode("\n", $rawdata); + } + + // loop through our received messages + while (count($rawdataar) > 0) { + $rawline = array_shift($rawdataar); + $validmessage = false; + + $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: received: "'.$rawline.'"', __FILE__, __LINE__); + + // building our data packet + $ircdata = new Net_SmartIRC_data(); + $ircdata->rawmessage = $rawline; + $lineex = explode(' ', $rawline); + $ircdata->rawmessageex = $lineex; + $messagecode = $lineex[0]; + + if (substr($rawline, 0, 1) == ':') { + $validmessage = true; + $line = substr($rawline, 1); + $lineex = explode(' ', $line); + + // conform to RFC 2812 + $from = $lineex[0]; + // Fix for ZNC. + $messagecode = (isset($lineex[1]) ? $lineex[1] : ''); + $exclamationpos = strpos($from, '!'); + $atpos = strpos($from, '@'); + $colonpos = strpos($line, ' :'); + if ($colonpos !== false) { + // we want the exact position of ":" not beginning from the space + $colonpos += 1; + } + $ircdata->nick = substr($from, 0, $exclamationpos); + $ircdata->ident = substr($from, $exclamationpos+1, ($atpos-$exclamationpos)-1); + $ircdata->host = substr($from, $atpos+1); + $ircdata->type = $this->_gettype($rawline); + $ircdata->from = $from; + if ($colonpos !== false) { + $ircdata->message = substr($line, $colonpos+1); + $ircdata->messageex = explode(' ', $ircdata->message); + } + + if ($ircdata->type & (SMARTIRC_TYPE_CHANNEL| + SMARTIRC_TYPE_ACTION| + SMARTIRC_TYPE_MODECHANGE| + SMARTIRC_TYPE_TOPICCHANGE| + SMARTIRC_TYPE_KICK| + SMARTIRC_TYPE_PART| + SMARTIRC_TYPE_JOIN)) { + $ircdata->channel = $lineex[2]; + } else if ($ircdata->type & (SMARTIRC_TYPE_WHO| + SMARTIRC_TYPE_BANLIST| + SMARTIRC_TYPE_TOPIC| + SMARTIRC_TYPE_CHANNELMODE)) { + $ircdata->channel = $lineex[3]; + } else if ($ircdata->type & SMARTIRC_TYPE_NAME) { + $ircdata->channel = $lineex[4]; + } + + if ($ircdata->channel !== null) { + if (substr($ircdata->channel, 0, 1) == ':') { + $ircdata->channel = substr($ircdata->channel, 1); + } + } + + $this->log(SMARTIRC_DEBUG_MESSAGEPARSER, 'DEBUG_MESSAGEPARSER: ircdata nick: "'.$ircdata->nick. + '" ident: "'.$ircdata->ident. + '" host: "'.$ircdata->host. + '" type: "'.$ircdata->type. + '" from: "'.$ircdata->from. + '" channel: "'.$ircdata->channel. + '" message: "'.$ircdata->message. + '"', __FILE__, __LINE__); + } + + // lets see if we have a messagehandler for it + $this->_handlemessage($messagecode, $ircdata); + + if ($validmessage == true) { + // now the actionhandlers are comming + $this->_handleactionhandler($ircdata); + } + + if (isset($ircdata)) { + unset($ircdata); + } + } + return true; + } + + /** + * sends the pong for keeping alive + * + * Sends the PONG signal as reply of the PING from the IRC server. + * + * @param string $data + * @return void + * @access private + */ + protected function _pong($data) + { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: Ping? Pong!', __FILE__, __LINE__); + $this->_send('PONG '.$data, SMARTIRC_CRITICAL); + } + + /** + * returns the calculated selecttimeout value + * + * @return integer selecttimeout in microseconds + * @access private + */ + protected function _selecttimeout() + { + if ($this->_messagebuffersize == 0) { + $this->_selecttimeout = null; + + if ($this->_mintimer != false) { + $this->_calculateselecttimeout($this->_mintimer); + } + + if ($this->_autoreconnect == true) { + $this->_calculateselecttimeout($this->_rxtimeout*1000); + } + + $this->_calculateselecttimeout($this->_maxtimer); + return $this->_selecttimeout; + } else { + return $this->_senddelay; + } + } + + /** + * calculates the selecttimeout value + * + * @param int $microseconds + * @return void + * @access private + */ + protected function _calculateselecttimeout($microseconds) + { + if (($this->_selecttimeout > $microseconds) || $this->_selecttimeout === null) { + $this->_selecttimeout = $microseconds; + } + } + + /** + * updates _mintimer to the smallest timer interval + * + * @return void + * @access private + */ + protected function _updatemintimer() + { + $timerarray = array(); + foreach ($this->_timehandler as $values) { + $timerarray[] = $values->interval; + } + + $result = array_multisort($timerarray, SORT_NUMERIC, SORT_ASC); + if ($result == true && isset($timerarray[0])) { + $this->_mintimer = $timerarray[0]; + } else { + $this->_mintimer = false; + } + } + + /** + * reorders the actionhandler array, needed after removing one + * + * @return void + * @access private + */ + protected function _reorderactionhandler() + { + $orderedactionhandler = array(); + foreach ($this->_actionhandler as $value) { + $orderedactionhandler[] = $value; + } + $this->_actionhandler = &$orderedactionhandler; + } + + /** + * reorders the timehandler array, needed after removing one + * + * @return void + * @access private + */ + protected function _reordertimehandler() + { + $orderedtimehandler = array(); + foreach ($this->_timehandler as $value) { + $orderedtimehandler[] = $value; + } + $this->_timehandler = &$orderedtimehandler; + } + + /** + * reorders the modules array, needed after removing one + * + * @return void + * @access private + */ + protected function _reordermodules() + { + $orderedmodules = array(); + foreach ($this->_modules as $value) { + $orderedmodules[] = $value; + } + $this->_modules = &$orderedmodules; + } + + /** + * determines the messagetype of $line + * + * Analyses the type of an IRC message and returns the type. + * + * @param string $line + * @return integer SMARTIRC_TYPE_* constant + * @access private + */ + protected function _gettype($line) + { + if (preg_match('/^:[^ ]+? [0-9]{3} .+$/', $line) == 1) { + $lineex = explode(' ', $line); + $code = $lineex[1]; + + switch ($code) { + case SMARTIRC_RPL_WELCOME: + case SMARTIRC_RPL_YOURHOST: + case SMARTIRC_RPL_CREATED: + case SMARTIRC_RPL_MYINFO: + case SMARTIRC_RPL_BOUNCE: + return SMARTIRC_TYPE_LOGIN; + case SMARTIRC_RPL_LUSERCLIENT: + case SMARTIRC_RPL_LUSEROP: + case SMARTIRC_RPL_LUSERUNKNOWN: + case SMARTIRC_RPL_LUSERME: + case SMARTIRC_RPL_LUSERCHANNELS: + return SMARTIRC_TYPE_INFO; + case SMARTIRC_RPL_MOTDSTART: + case SMARTIRC_RPL_MOTD: + case SMARTIRC_RPL_ENDOFMOTD: + return SMARTIRC_TYPE_MOTD; + case SMARTIRC_RPL_NAMREPLY: + case SMARTIRC_RPL_ENDOFNAMES: + return SMARTIRC_TYPE_NAME; + case SMARTIRC_RPL_WHOREPLY: + case SMARTIRC_RPL_ENDOFWHO: + return SMARTIRC_TYPE_WHO; + case SMARTIRC_RPL_LISTSTART: + return SMARTIRC_TYPE_NONRELEVANT; + case SMARTIRC_RPL_LIST: + case SMARTIRC_RPL_LISTEND: + return SMARTIRC_TYPE_LIST; + case SMARTIRC_RPL_BANLIST: + case SMARTIRC_RPL_ENDOFBANLIST: + return SMARTIRC_TYPE_BANLIST; + case SMARTIRC_RPL_TOPIC: + return SMARTIRC_TYPE_TOPIC; + case SMARTIRC_RPL_WHOISUSER: + case SMARTIRC_RPL_WHOISSERVER: + case SMARTIRC_RPL_WHOISOPERATOR: + case SMARTIRC_RPL_WHOISIDLE: + case SMARTIRC_RPL_ENDOFWHOIS: + case SMARTIRC_RPL_WHOISCHANNELS: + return SMARTIRC_TYPE_WHOIS; + case SMARTIRC_RPL_WHOWASUSER: + case SMARTIRC_RPL_ENDOFWHOWAS: + return SMARTIRC_TYPE_WHOWAS; + case SMARTIRC_RPL_UMODEIS: + return SMARTIRC_TYPE_USERMODE; + case SMARTIRC_RPL_CHANNELMODEIS: + return SMARTIRC_TYPE_CHANNELMODE; + case SMARTIRC_ERR_NICKNAMEINUSE: + case SMARTIRC_ERR_NOTREGISTERED: + return SMARTIRC_TYPE_ERROR; + default: + $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: replycode UNKNOWN ('.$code.'): "'.$line.'"', __FILE__, __LINE__); + } + } + + if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'ACTION .*'.chr(1).'$/', $line) == 1) { + return SMARTIRC_TYPE_ACTION; + } else if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'.*'.chr(1).'$/', $line) == 1) { + return (SMARTIRC_TYPE_CTCP_REQUEST|SMARTIRC_TYPE_CTCP); + } else if (preg_match('/^:.*? NOTICE .* :'.chr(1).'.*'.chr(1).'$/', $line) == 1) { + return (SMARTIRC_TYPE_CTCP_REPLY|SMARTIRC_TYPE_CTCP); + } else if (preg_match('/^:.*? PRIVMSG (\&|\#|\+|\!).* :.*$/', $line) == 1) { + return SMARTIRC_TYPE_CHANNEL; + } else if (preg_match('/^:.*? PRIVMSG .*:.*$/', $line) == 1) { + return SMARTIRC_TYPE_QUERY; + } else if (preg_match('/^:.*? NOTICE .* :.*$/', $line) == 1) { + return SMARTIRC_TYPE_NOTICE; + } else if (preg_match('/^:.*? INVITE .* .*$/', $line) == 1) { + return SMARTIRC_TYPE_INVITE; + } else if (preg_match('/^:.*? JOIN .*$/', $line) == 1) { + return SMARTIRC_TYPE_JOIN; + } else if (preg_match('/^:.*? TOPIC .* :.*$/', $line) == 1) { + return SMARTIRC_TYPE_TOPICCHANGE; + } else if (preg_match('/^:.*? NICK .*$/', $line) == 1) { + return SMARTIRC_TYPE_NICKCHANGE; + } else if (preg_match('/^:.*? KICK .* .*$/', $line) == 1) { + return SMARTIRC_TYPE_KICK; + } else if (preg_match('/^:.*? PART .*$/', $line) == 1) { + return SMARTIRC_TYPE_PART; + } else if (preg_match('/^:.*? MODE .* .*$/', $line) == 1) { + return SMARTIRC_TYPE_MODECHANGE; + } else if (preg_match('/^:.*? QUIT :.*$/', $line) == 1) { + return SMARTIRC_TYPE_QUIT; + } else { + $this->log(SMARTIRC_DEBUG_MESSAGETYPES, 'DEBUG_MESSAGETYPES: SMARTIRC_TYPE_UNKNOWN!: "'.$line.'"', __FILE__, __LINE__); + return SMARTIRC_TYPE_UNKNOWN; + } + } + + /** + * updates the current connection state + * + * @return boolean + * @access private + */ + protected function _updatestate() + { + if (is_resource($this->_socket)) { + $rtype = get_resource_type($this->_socket); + if (($this->_socket !== false) && + ($rtype == 'socket' || $rtype == 'Socket' || $rtype == 'stream')) { + $this->_state = true; + return true; + } + } else { + $this->_state = false; + $this->_loggedin = false; + } + return false; + } + + /** + * returns the current connection state + * + * @return integer SMARTIRC_STATE_CONNECTED or SMARTIRC_STATE_DISCONNECTED + * @access private + */ + protected function _state() + { + $result = $this->_updatestate(); + + if ($result == true) { + return SMARTIRC_STATE_CONNECTED; + } else { + return SMARTIRC_STATE_DISCONNECTED; + } + } + + /** + * tries to find a messagehandler for the received message ($ircdata) and calls it + * + * @param string $messagecode + * @param object $ircdata + * @return void + * @access private + */ + protected function _handlemessage($messagecode, &$ircdata) + { + $found = false; + $_methodname = $methodname = $_codetype = ''; + + if (is_numeric($messagecode)) { + if (!array_key_exists($messagecode, $this->nreplycodes)) { + $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: ignoring unrecognized messagecode! "'.$messagecode.'"', __FILE__, __LINE__); + $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: this IRC server ('.$this->_address.') doesn\'t conform to the RFC 2812!', __FILE__, __LINE__); + return; + } + + $methodname = 'event_'.strtolower($this->nreplycodes[$messagecode]); + $_methodname = '_'.$methodname; + $_codetype = 'by numeric'; + } else if (is_string($messagecode)) { // its not numericcode so already a name/string + $methodname = 'event_'.strtolower($messagecode); + $_methodname = '_'.$methodname; + $_codetype = 'by string'; + } + + // if exists call internal method for the handling + if (@method_exists($this, $_methodname)) { + $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: calling internal method "'.get_class($this).'->'.$_methodname.'" ('.$_codetype.')', __FILE__, __LINE__); + $this->$_methodname($ircdata); + $found = true; + } + + // if exist, call user defined method for the handling + if (@method_exists($this, $methodname)) { + $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: calling user defined method "'.get_class($this).'->'.$methodname.'" ('.$_codetype.')', __FILE__, __LINE__); + $this->$methodname($ircdata); + $found = true; + } + + if ($found == false) { + $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: no method found for "'.$messagecode.'" ('.$methodname.')', __FILE__, __LINE__); + } + } + + /** + * Strips control characters from a IRC message. + * + * @param string $text + * + * @return string + */ + protected function _stripControlCharacters($text) { + $controlCodes = array( + '/(\x03(?:\d{1,2}(?:,\d{1,2})?)?)/', // Color code + '/\x02/', // Bold + '/\x0F/', // Escaped + '/\x16/', // Italic + '/\x1F/', // Underline + '/\x12/' + ); + return preg_replace($controlCodes,'',$text); + } + + /** + * tries to find a actionhandler for the received message ($ircdata) and calls it + * + * @param object $ircdata + * @return void + * @access private + */ + protected function _handleactionhandler(&$ircdata) + { + $handler = &$this->_actionhandler; + $handlercount = count($handler); + for ($i = 0; $i < $handlercount; $i++) { + $handlerobject = &$handler[$i]; + + if (substr($handlerobject->message, 0, 1) == '/') { + $regex = $handlerobject->message; + } else { + $regex = '/'.$handlerobject->message.'/'; + } + + $ircdata->message = $this->_stripControlCharacters($ircdata->message); + if (($handlerobject->type & $ircdata->type) && + (preg_match($regex, $ircdata->message) == 1)) { + + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler match found for id: '.$i.' type: '.$ircdata->type.' message: "'.$ircdata->message.'" regex: "'.$regex.'"', __FILE__, __LINE__); + + $methodobject = &$handlerobject->object; + $method = $handlerobject->method; + + if (@method_exists($methodobject, $method)) { + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__); + $methodobject->$method($this, $ircdata); + } else { + $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: method doesn\'t exist! "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__); + } + } + } + } + + /** + * Delay reconnect + * + * @return void + * @access private + */ + protected function _delayReconnect() + { + if ($this->_reconnectdelay > 0) { + $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: delaying reconnect for '.$this->_reconnectdelay.' ms', __FILE__, __LINE__); + usleep($this->_reconnectdelay * 1000); + } + } + + /** + * getting current microtime, needed for benchmarks + * + * @return float + * @access private + */ + protected function _microint() + { + $tmp = microtime(); + $parts = explode(' ', $tmp); + $floattime = (float)$parts[0] + (float)$parts[1]; + return $floattime; + } + + /** + * adds an user to the channelobject or updates his info + * + * @param object $channel + * @param object $newuser + * @return void + * @access private + */ + protected function _adduser(&$channel, &$newuser) + { + $lowerednick = strtolower($newuser->nick); + if ($this->isJoined($channel->name, $newuser->nick)) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: updating user: '.$newuser->nick.' on channel: '.$channel->name, __FILE__, __LINE__); + + // lets update the existing user + $currentuser = &$channel->users[$lowerednick]; + + if ($newuser->ident !== null) { + $currentuser->ident = $newuser->ident; + } + if ($newuser->host !== null) { + $currentuser->host = $newuser->host; + } + if ($newuser->realname !== null) { + $currentuser->realname = $newuser->realname; + } + if ($newuser->ircop !== null) { + $currentuser->ircop = $newuser->ircop; + } + if ($newuser->founder !== null) { + $currentuser->founder = $newuser->founder; + } + if ($newuser->admin !== null) { + $currentuser->admin = $newuser->admin; + } + if ($newuser->op !== null) { + $currentuser->op = $newuser->op; + } + if ($newuser->hop !== null) { + $currentuser->hop = $newuser->hop; + } + if ($newuser->voice !== null) { + $currentuser->voice = $newuser->voice; + } + if ($newuser->away !== null) { + $currentuser->away = $newuser->away; + } + if ($newuser->server !== null) { + $currentuser->server = $newuser->server; + } + if ($newuser->hopcount !== null) { + $currentuser->hopcount = $newuser->hopcount; + } + } else { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding user: '.$newuser->nick.' to channel: '.$channel->name, __FILE__, __LINE__); + + // he is new just add the reference to him + $channel->users[$lowerednick] = &$newuser; + } + + $user = &$channel->users[$lowerednick]; + if ($user->founder) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding founder: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); + $channel->founders[$user->nick] = true; + } + if ($user->admin) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding admin: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); + $channel->admins[$user->nick] = true; + } + if ($user->op) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding op: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); + $channel->ops[$user->nick] = true; + } + if ($user->hop) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding half-op: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); + $channel->hops[$user->nick] = true; + } + if ($user->voice) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding voice: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__); + $channel->voices[$user->nick] = true; + } + } + + /** + * removes an user from one channel or all if he quits + * + * @param object $ircdata + * @return void + * @access private + */ + protected function _removeuser(&$ircdata) + { + if ($ircdata->type & (SMARTIRC_TYPE_PART|SMARTIRC_TYPE_QUIT)) { + $nick = $ircdata->nick; + } else if ($ircdata->type & SMARTIRC_TYPE_KICK) { + $nick = $ircdata->rawmessageex[3]; + } else { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: unknown TYPE ('.$ircdata->type.') in _removeuser(), trying default', __FILE__, __LINE__); + $nick = $ircdata->nick; + } + + $lowerednick = strtolower($nick); + + if ($this->_nick == $nick) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: we left channel: '.$ircdata->channel.' destroying...', __FILE__, __LINE__); + unset($this->_channels[strtolower($ircdata->channel)]); + } else { + if ($ircdata->type & SMARTIRC_TYPE_QUIT) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: user '.$nick.' quit, removing him from all channels', __FILE__, __LINE__); + // remove the user from all channels + $channelkeys = array_keys($this->_channels); + foreach ($channelkeys as $channelkey) { + // loop through all channels + $channel = &$this->_channels[$channelkey]; + foreach ($channel->users as $uservalue) { + // loop through all user in this channel + if ($nick == $uservalue->nick) { + // found him + // kill him + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: found him on channel: '.$channel->name.' destroying...', __FILE__, __LINE__); + unset($channel->users[$lowerednick]); + + if (isset($channel->founders[$nick])) { + // die! + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from founder list', __FILE__, __LINE__); + unset($channel->founders[$nick]); + } + + if (isset($channel->admins[$nick])) { + // die! + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from admin list', __FILE__, __LINE__); + unset($channel->admins[$nick]); + } + + if (isset($channel->ops[$nick])) { + // die! + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from op list', __FILE__, __LINE__); + unset($channel->ops[$nick]); + } + + if (isset($channel->hops[$nick])) { + // die! + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from hop list', __FILE__, __LINE__); + unset($channel->hops[$nick]); + } + + if (isset($channel->voices[$nick])) { + // die!! + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from voice list', __FILE__, __LINE__); + unset($channel->voices[$nick]); + } + + // ups this was not DukeNukem 3D + } + } + } + } else { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing user: '.$nick.' from channel: '.$ircdata->channel, __FILE__, __LINE__); + $channel = &$this->_channels[strtolower($ircdata->channel)]; + unset($channel->users[$lowerednick]); + + if (isset($channel->founders[$nick])) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from founder list', __FILE__, __LINE__); + unset($channel->founders[$nick]); + } + + if (isset($channel->admins[$nick])) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from admin list', __FILE__, __LINE__); + unset($channel->admins[$nick]); + } + + if (isset($channel->ops[$nick])) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from op list', __FILE__, __LINE__); + unset($channel->ops[$nick]); + } + + if (isset($channel->hops[$nick])) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from hop list', __FILE__, __LINE__); + unset($channel->hops[$nick]); + } + + if (isset($channel->voices[$nick])) { + $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from voice list', __FILE__, __LINE__); + unset($channel->voices[$nick]); + } + } + } + } + + /** + * checks if the passed handlertype is valid + * + * @param integer $handlertype + * @return boolean + * @access private + */ + protected function _isValidType($handlertype) { + if ($handlertype & SMARTIRC_TYPE_ALL) { + return true; + } else { + return false; + } + } + + protected function isError($object) + { + return (bool)(is_object($object) && (strtolower(get_class($object)) == 'net_smartirc_error')); + } + } // includes must be after the base class definition, required for PHP5 @@ -2899,7 +2865,7 @@ require_once 'SmartIRC/messagehandler.php'; class Net_SmartIRC extends Net_SmartIRC_messagehandler { - // empty + // empty } /** @@ -2907,65 +2873,65 @@ class Net_SmartIRC extends Net_SmartIRC_messagehandler */ class Net_SmartIRC_data { - /** - * @var string - * @access public - */ - var $from; + /** + * @var string + * @access public + */ + var $from; - /** - * @var string - * @access public - */ - var $nick; + /** + * @var string + * @access public + */ + var $nick; - /** - * @var string - * @access public - */ - var $ident; + /** + * @var string + * @access public + */ + var $ident; - /** - * @var string - * @access public - */ - var $host; + /** + * @var string + * @access public + */ + var $host; - /** - * @var string - * @access public - */ - var $channel; + /** + * @var string + * @access public + */ + var $channel; - /** - * @var string - * @access public - */ - var $message; + /** + * @var string + * @access public + */ + var $message; - /** - * @var array - * @access public - */ - var $messageex = array(); + /** + * @var array + * @access public + */ + var $messageex = array(); - /** - * @var integer - * @access public - */ - var $type; + /** + * @var integer + * @access public + */ + var $type; - /** - * @var string - * @access public - */ - var $rawmessage; + /** + * @var string + * @access public + */ + var $rawmessage; - /** - * @var array - * @access public - */ - var $rawmessageex = array(); + /** + * @var array + * @access public + */ + var $rawmessageex = array(); } /** @@ -2973,35 +2939,35 @@ class Net_SmartIRC_data */ class Net_SmartIRC_actionhandler { - /** - * @var integer - * @access public - */ - var $id; + /** + * @var integer + * @access public + */ + var $id; - /** - * @var integer - * @access public - */ - var $type; + /** + * @var integer + * @access public + */ + var $type; - /** - * @var string - * @access public - */ - var $message; + /** + * @var string + * @access public + */ + var $message; - /** - * @var object - * @access public - */ - var $object; + /** + * @var object + * @access public + */ + var $object; - /** - * @var string - * @access public - */ - var $method; + /** + * @var string + * @access public + */ + var $method; } /** @@ -3009,35 +2975,35 @@ class Net_SmartIRC_actionhandler */ class Net_SmartIRC_timehandler { - /** - * @var integer - * @access public - */ - var $id; + /** + * @var integer + * @access public + */ + var $id; - /** - * @var integer - * @access public - */ - var $interval; + /** + * @var integer + * @access public + */ + var $interval; - /** - * @var integer - * @access public - */ - var $lastmicrotimestamp; + /** + * @var integer + * @access public + */ + var $lastmicrotimestamp; - /** - * @var object - * @access public - */ - var $object; + /** + * @var object + * @access public + */ + var $object; - /** - * @var string - * @access public - */ - var $method; + /** + * @var string + * @access public + */ + var $method; } /** @@ -3045,95 +3011,95 @@ class Net_SmartIRC_timehandler */ class Net_SmartIRC_channel { - /** - * @var string - * @access public - */ - var $name; + /** + * @var string + * @access public + */ + var $name; - /** - * @var string - * @access public - */ - var $key; + /** + * @var string + * @access public + */ + var $key; - /** - * @var array - * @access public - */ - var $users = array(); + /** + * @var array + * @access public + */ + var $users = array(); - /** - * @var array - * @access public - */ - var $founders = array(); + /** + * @var array + * @access public + */ + var $founders = array(); - /** - * @var array - * @access public - */ - var $admins = array(); + /** + * @var array + * @access public + */ + var $admins = array(); - /** - * @var array - * @access public - */ - var $ops = array(); + /** + * @var array + * @access public + */ + var $ops = array(); - /** - * @var array - * @access public - */ - var $hops = array(); + /** + * @var array + * @access public + */ + var $hops = array(); - /** - * @var array - * @access public - */ - var $voices = array(); + /** + * @var array + * @access public + */ + var $voices = array(); - /** - * @var array - * @access public - */ - var $bans = array(); + /** + * @var array + * @access public + */ + var $bans = array(); - /** - * @var string - * @access public - */ - var $topic; + /** + * @var string + * @access public + */ + var $topic; - /** - * @var string - * @access public - */ - var $user_limit = false; + /** + * @var string + * @access public + */ + var $user_limit = false; - /** - * @var string - * @access public - */ - var $mode; + /** + * @var string + * @access public + */ + var $mode; - /** - * @var integer - * @access public - */ - var $synctime_start = 0; + /** + * @var integer + * @access public + */ + var $synctime_start = 0; - /** - * @var integer - * @access public - */ - var $synctime_stop = 0; + /** + * @var integer + * @access public + */ + var $synctime_stop = 0; - /** - * @var integer - * @access public - */ - var $synctime; + /** + * @var integer + * @access public + */ + var $synctime; } /** @@ -3141,53 +3107,53 @@ class Net_SmartIRC_channel */ class Net_SmartIRC_user { - /** - * @var string - * @access public - */ - var $nick; + /** + * @var string + * @access public + */ + var $nick; - /** - * @var string - * @access public - */ - var $ident; + /** + * @var string + * @access public + */ + var $ident; - /** - * @var string - * @access public - */ - var $host; + /** + * @var string + * @access public + */ + var $host; - /** - * @var string - * @access public - */ - var $realname; + /** + * @var string + * @access public + */ + var $realname; - /** - * @var boolean - * @access public - */ - var $ircop; + /** + * @var boolean + * @access public + */ + var $ircop; - /** - * @var boolean - * @access public - */ - var $away; + /** + * @var boolean + * @access public + */ + var $away; - /** - * @var string - * @access public - */ - var $server; + /** + * @var string + * @access public + */ + var $server; - /** - * @var integer - * @access public - */ - var $hopcount; + /** + * @var integer + * @access public + */ + var $hopcount; } /** @@ -3195,35 +3161,35 @@ class Net_SmartIRC_user */ class Net_SmartIRC_channeluser extends Net_SmartIRC_user { - /** - * @var boolean - * @access public - */ - var $founder; + /** + * @var boolean + * @access public + */ + var $founder; - /** - * @var boolean - * @access public - */ - var $admin; + /** + * @var boolean + * @access public + */ + var $admin; - /** - * @var boolean - * @access public - */ - var $op; + /** + * @var boolean + * @access public + */ + var $op; - /** - * @var boolean - * @access public - */ - var $hop; + /** + * @var boolean + * @access public + */ + var $hop; - /** - * @var boolean - * @access public - */ - var $voice; + /** + * @var boolean + * @access public + */ + var $voice; } /** @@ -3231,11 +3197,11 @@ class Net_SmartIRC_channeluser extends Net_SmartIRC_user */ class Net_SmartIRC_ircuser extends Net_SmartIRC_user { - /** - * @var array - * @access public - */ - var $joinedchannels = array(); + /** + * @var array + * @access public + */ + var $joinedchannels = array(); } /** @@ -3243,39 +3209,38 @@ class Net_SmartIRC_ircuser extends Net_SmartIRC_user */ class Net_SmartIRC_listenfor { - /** - * @var array - * @access public - */ - var $result = array(); + /** + * @var array + * @access public + */ + var $result = array(); - /** - * stores the received answer into the result array - * - * @param object $irc - * @param object $ircdata - * @return void - */ - function handler(&$irc, &$ircdata) - { - $irc->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: listenfor handler called', __FILE__, __LINE__); - $this->result[] = $ircdata; - $irc->disconnect(true); - } + /** + * stores the received answer into the result array + * + * @param object $irc + * @param object $ircdata + * @return void + */ + function handler(&$irc, &$ircdata) + { + $irc->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: listenfor handler called', __FILE__, __LINE__); + $this->result[] = $ircdata; + $irc->disconnect(true); + } } class Net_SmartIRC_Error { - var $error_msg; + var $error_msg; - function __construct($message) - { - $this->error_msg = $message; - } + function __construct($message) + { + $this->error_msg = $message; + } - function getMessage() - { - return $this->error_msg; - } -} -?> + function getMessage() + { + return $this->error_msg; + } +} \ No newline at end of file diff --git a/lib/Net_SmartIRC/Net/SmartIRC/irccommands.php b/lib/Net_SmartIRC/Net/SmartIRC/irccommands.php index a85f37f07..9e33857b9 100644 --- a/lib/Net_SmartIRC/Net/SmartIRC/irccommands.php +++ b/lib/Net_SmartIRC/Net/SmartIRC/irccommands.php @@ -105,7 +105,7 @@ class Net_SmartIRC_irccommands extends Net_SmartIRC_base * * @param array $channelarray ; array('#channelname1' => 'password', '#channelname2' => null); * @param integer $priority message priority, default is SMARTIRC_MEDIUM - * @return void + * @return bool * @access public */ function join($channelarray, $priority = SMARTIRC_MEDIUM) @@ -113,6 +113,7 @@ class Net_SmartIRC_irccommands extends Net_SmartIRC_base foreach ($channelarray as $channel => $password) { $this->_send('JOIN ' . $channel . ($password === null ? '' : ' ' . $password), $priority); } + return true; } /** @@ -522,5 +523,4 @@ class Net_SmartIRC_irccommands extends Net_SmartIRC_base $this->disconnect(true); } -} -?> +} \ No newline at end of file diff --git a/lib/Net_SmartIRC/Net/SmartIRC/messagehandler.php b/lib/Net_SmartIRC/Net/SmartIRC/messagehandler.php index 8ff8358ff..187ae75dc 100644 --- a/lib/Net_SmartIRC/Net/SmartIRC/messagehandler.php +++ b/lib/Net_SmartIRC/Net/SmartIRC/messagehandler.php @@ -523,5 +523,4 @@ class Net_SmartIRC_messagehandler extends Net_SmartIRC_irccommands { $this->_nicknameinuse(); } -} -?> +} \ No newline at end of file diff --git a/lib/prehash.php b/lib/prehash.php index fe067c249..cf9a36402 100644 --- a/lib/prehash.php +++ b/lib/prehash.php @@ -10,6 +10,8 @@ require_once("consoletools.php"); require_once("ColorCLI.php"); require_once("nzbcontents.php"); require_once("simple_html_dom.php"); +require_once("IRCScraper.php"); + /* * Class for inserting names/categories/md5 etc from predb sources into the DB, also for matching names on files / subjects. @@ -39,6 +41,7 @@ Class PreHash $this->echooutput = $echooutput; $this->db = new DB(); $this->c = new ColorCLI; + $this->functions = new Functions(); } // Retrieve pre info from predb sources and store them in the DB. @@ -177,7 +180,7 @@ Class PreHash { $db = new DB(); $f = new Functions(); - $newnames = $updated = 0; + $newNames = $updated = 0; $matches2 = $matches = $match = $m = ''; $buffer = $this->fileContents('http://www.newshost.co.za'); @@ -226,7 +229,7 @@ Class PreHash if (strlen($matches2['title']) > 15) { if($db->exec(sprintf("INSERT INTO prehash (title, nfo, size, category, predate, source, md5) VALUES (%s, %s, %s, %s, FROM_UNIXTIME(".strtotime($matches2["date"])."), %s, %s)", $db->escapeString($matches2["title"]), $nfo, $size, $db->escapeString($matches2["category"]), $db->escapeString("womble"), $md5)));{ - $newnames++; + $newNames++; } } } @@ -240,14 +243,14 @@ Class PreHash { echo $this->c->error("Update from Womble failed."); } - return $newnames; + return $newNames; } public function retrieveOmgwtfnzbs() { $db = new DB(); $f = new Functions(); - $newnames = $updated = 0; + $newNames = $updated = 0; $matches2 = $matches = $match = $m = ''; $buffer = $this->fileContents('http://rss.omgwtfnzbs.org/rss-info.php'); @@ -259,47 +262,59 @@ Class PreHash { foreach ($match as $m) { - if (preg_match('/(?P<title>.+?)<\/title.+?pubDate>(?P<date>.+?)<\/pubDate.+?gory:<\/b> (?P<category>.+?)<br \/.+?<\/b> (?P<size1>.+?) (?P<size2>[a-zA-Z]+)<b/s', $m, $matches2)) - { - $title = preg_replace('/\s+- omgwtfnzbs\.org/', '', $matches2['title']); - $md5 = $db->escapeString(md5($title)); - $oldname = $db->queryOneRow(sprintf('SELECT md5, source, ID FROM prehash WHERE md5 = %s', $md5)); - if ($oldname !== false) { - if ($oldname['source'] == 'womble' || $oldname['source'] == 'omgwtfnzbs') { - continue; - } else { - $size = $db->escapeString(round($matches2["size1"]).$matches2["size2"]); - $db->exec(sprintf("UPDATE prehash SET size = %s, category = %s, predate = FROM_UNIXTIME(".strtotime($matches2["date"])."), source = %s where ID = %d", $size, $db->escapeString($matches2["category"]), $db->escapeString("omgwtfnzbs"), $oldname["ID"])); - $updated++; - } + if (preg_match('/<title>(?P<title>.+?)\s+-\s+omgwtfnzbs\.org.*?<\/title.+?pubDate>(?P<date>.+?)<\/pubDate.+?gory:<\/b> (?P<category>.+?)<br \/.+?<\/b> (?P<size1>.+?) (?P<size2>[a-zA-Z]+)<b/s', $m, $matches2)) { + // If the title is too short, don't bother. + if (strlen($matches2['title']) < 15) { + continue; } - else - { - $size = $db->escapeString(round($matches2["size1"]).$matches2["size2"]); - if (strlen($title) > 15) { - if($db->exec(sprintf("INSERT INTO prehash (title, size, category, predate, source, md5) VALUES (%s, %s, %s, FROM_UNIXTIME(".strtotime($matches2["date"])."), %s, %s)", $db->escapeString($title), $size, $db->escapeString($matches2["category"]), $db->escapeString("omgwtfnzbs"),$md5))); { - $newnames++; - } - } + $title = $matches2['title']; + $md5 = $this->db->escapeString(md5($title)); + $oldName = $this->db->queryOneRow(sprintf('SELECT md5, source, ID FROM prehash WHERE md5 = %s', $md5)); + // If we have it already and the source is womble or omg, continue. + if ($oldName !== false && ($oldName['source'] === 'womble' || $oldName['source'] === 'omgwtfnzbs')) { + continue; + } + $size = $this->db->escapeString(round($matches2['size1']) . $matches2['size2']); + $category = $this->db->escapeString($matches2['category']); + $time = $this->functions->from_unixtime(strtotime($matches2['date'])); + $source = $this->db->escapeString('omgwtfnzbs'); + + // If we have it already, update it. + if ($oldName !== false) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET size = %s, category = %s, predate = %s, source = %s + WHERE ID = %d', + $size, $category, $time, $source, $oldName['ID'] + ) + ); + $updated++; + } elseif ($this->db->exec( + sprintf(' + INSERT INTO prehash (title, size, category, predate, source, md5) + VALUES (%s, %s, %s, %s, %s, %s)', + $this->db->escapeString($title), $size, $category, $time, $source, $md5))) { + $newNames++; } } } } } - echo $this->c->primary($updated . " \tUpdated from Omgwtfnzbs."); - } - else - { + if ($this ->echooutput) { + echo $this->c->primary($updated . " \tUpdated from Omgwtfnzbs."); + } + } elseif ($this ->echooutput) { echo $this->c->error("Update from Omgwtfnzbs failed."); } - return $newnames; + return $newNames; } public function retrieveZenet() { $db = new DB(); $f = new Functions(); - $newnames = $updated = 0; + $newNames = $updated = 0; $matches2 = $matches = $match = $m = ''; $buffer = $this->fileContents('http://pre.zenet.org/live.php'); @@ -311,206 +326,240 @@ Class PreHash { foreach ($match as $m) { - if (preg_match('/<span class="bold">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2})<\/span>.+<a href="\?post=\d+"><b><font color="#\d+">(?P<title>.+)<\/font><\/b><\/a>.+<p><a href="\?cats=.+"><font color="#FF9900">(?P<category>.+)<\/font><\/a> \| (?P<size1>[\d\.,]+)?(?P<size2>[MGK]B)? \/.+<\/div>/s', $m, $matches2)) - { - $md5 = $db->escapeString(md5($matches2['title'])); - $title = $db->escapeString($matches2['title']); - $dupeCheck = $db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); - if ($dupeCheck !== false) { - continue; - } else { - if (!isset($matches2['size1']) && empty($matches2['size1'])) { - $size = 'NULL'; - } else { - $size = $db->escapeString(round($matches2['size1']).$matches2['size2']); - } - if (isset($matches2['category']) && !empty($matches2['category'])) { - $category = $db->escapeString($matches2['category']); - } else { - $category = 'NULL'; - } - if (strlen($title) > 15) { - if ($db->queryInsert(sprintf('INSERT INTO prehash (title, size, category, predate, source, md5) VALUES (%s, %s, %s, %s, %s, %s)', $title, $size, $category, $db->escapeString($matches2['predate']), $db->escapeString('zenet'), $md5)));{ - $newnames++; - } - } - } - } - } - } - } - } - else - { - echo $this->c->error("Update from Zenet failed."); - } - return $newnames; - } + if (preg_match('/<span class="bold">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2})<\/span>.+<a href="\?post=\d+"><b><font color="#\d+">(?P<title>.+)<\/font><\/b><\/a>.+<p><a href="\?cats=.+"><font color="#FF9900">(?P<category>.+)<\/font><\/a> \| (?P<size1>[\d\.,]+)?(?P<size2>[MGK]B)? \/\s+(?P<files>\d+).+<\/div>/s', $m, $matches2)) { - public function retrievePrelist() - { - $db = new DB(); - $f = new Functions(); - $newnames = $updated = 0; - $matches2 = $matches = $match = $m = ''; - - $buffer = $this->fileContents('http://www.prelist.ws/'); - if ($buffer !== false && strlen($buffer)) - { - if (preg_match_all('/<small><span.+?<\/span><\/small>/s', $buffer, $matches)) - { - foreach ($matches as $match) - { - foreach ($match as $m) - { - if (!preg_match('/NUKED/', $m) && preg_match('/">\[ (?P<date>.+?) U.+?">(?P<category>.+?)<\/a>.+?">(?P<title>.+?)<\/a>.+?(b>\[ (?P<size>.+?) \]<\/b)?/si', $m, $matches2)) - { - $md5 = $db->escapeString(md5($matches2['title'])); - $oldname = $db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); - if ($oldname !== false) { + // If it's too short, don't bother. + if (strlen($matches2['title']) < 15) { continue; - } - else - { - if (!isset($matches2["size"]) && empty($matches2["size"])){ - $size = "NULL"; - } else { - $size = $db->escapeString(round($matches2["size"])); - } - if (strlen($matches2['title']) > 15) { - if($db->exec(sprintf("INSERT INTO prehash (title, size, category, predate, source, md5) VALUES (%s, %s, %s, FROM_UNIXTIME(".strtotime($matches2["date"])."), %s, %s)", $db->escapeString($matches2["title"]), $size, $db->escapeString($matches2["category"]), $db->escapeString("prelist"), $md5)));{ - $newnames++; - } - } } - } - else if (preg_match('/">\[ (?P<date>.+?) U.+?">(?P<category>.+?)<\/a>.+?">(?P<category1>.+?)<\/a.+">(?P<title>.+?)<\/a>/si', $m, $matches2)) - { - $md5 = $db->escapeString(md5($matches2['title'])); - $dupeCheck = $db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); + $md5 = $this->db->escapeString(md5($matches2['title'])); + $dupeCheck = $this->db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); if ($dupeCheck !== false) { - continue; - }else - { - $category = $db->escapeString($matches2["category"].", ".$matches2["category1"]); - if (strlen($matches2['title']) > 15) { - if($db->exec(sprintf("INSERT INTO prehash (title, category, predate, source, md5) VALUES (%s, %s, FROM_UNIXTIME(".strtotime($matches2["date"])."), %s, %s)", $db->escapeString($matches2["title"]), $category, $db->escapeString("prelist"), $md5))); { - $newnames++; - } - } + continue; + } elseif ($this->db->exec( + sprintf(' + INSERT INTO prehash (title, size, category, predate, source, md5, files) + VALUES (%s, %s, %s, %s, %s, %s, %s)', + $this->db->escapeString($matches2['title']), + ((!isset($matches2['size1']) && empty($matches2['size1'])) + ? 'NULL' + : $this->db->escapeString(round($matches2['size1']) . $matches2['size2']) + ), + ((isset($matches2['category']) && !empty($matches2['category'])) + ? $this->db->escapeString($matches2['category']) + : 'NULL' + ), + $this->functions->from_unixtime(strtotime($matches2['predate'])), + $this->db->escapeString('zenet'), + $md5, + $this->db->escapeString($matches2['files'])))) { + $newNames++; } } } } } + } elseif ($this->echooutput) { + echo $this->c->error("Update from Zenet failed."); } - else - { - echo $this->c->error("Update from Prelist failed."); - } - return $newnames; + return $newNames; } - public function retrieveOrlydb() + /** + * Get new pre from pre list. + * + * @note - Probably has to be remade. + * + * @return int + */ + protected function retrievePrelist() { - $db = new DB(); - $f = new Functions(); - $newnames = $updated = 0; - $matches2 = $matches = $match = $m = ''; + $newNames = 0; + $buffer = $this->getUrl('http://www.prelist.ws/'); + if ($buffer !== false) { + $matches = $matches2 = $matches3 = array(); + if (preg_match_all('/<div class="PreData ">.+?<\/div>\s*<\/div>\s*<\/div>/s', $buffer, $matches)) { + foreach($matches as $matches2) { + foreach ($matches2 as $matches3) { + if (preg_match('/">(?P<title>.+?)<\/a><\/div><div class="break".+?FiLTER">(?P<category>.+?)<\/a>.+?"Time">(?P<date>.+?)<\/div.+?"FilesSize">(?P<files>\d+F).*?(?P<size>\d+[KMGPT]?B).+?"Reason">(?P<reason>.*?)<\/div>/is', $matches3, $matches4)) { - $buffer = $this->fileContents('http://www.orlydb.com/'); - if ($buffer !== false && strlen($buffer)) - { - if (preg_match('/<div id="releases">(.+)<div id="pager">/s', $buffer, $match)) - { - if (preg_match_all('/<div>.+?<\/div>/s', $match["1"], $matches)) - { - foreach ($matches as $m1) - { - foreach ($m1 as $m) - { - if (preg_match('/timestamp">(?P<date>.+?)<\/span>.+?section">.+?">(?P<category>.+?)<\/a>.+?release">(?P<title>.+?)<\/span>(.+info">(?P<size>.+?) )?/s', $m, $matches2)) - { - $md5 = $db->escapeString(md5($matches2['title'])); - $oldname = $db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); - if ($oldname !== false) { + // Skip if too short. + if (strlen($matches4['title']) < 15) { + continue; + } + $md5 = $this->db->escapeString(md5($matches4['title'])); + $oldName = $this->db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); + + // If we have it already, skip. + if ($oldName !== false) { + continue; + } + + $nuked = $nukereason = ''; + if (!empty($matches4['reason'])) { + $nuked = IRCScraper::NUKE; + $nukereason = $matches4['reason']; + } + + if ($this->db->exec( + sprintf(' + INSERT INTO prehash (title, size, category, predate, source, md5, files, nuked, nukreason) + VALUES (%s, %s, %s, %s, %s, %s, %s)', + $this->db->escapeString($matches4['title']), + ((!isset($matches4['size']) && empty($matches4['size'])) + ? 'NULL' + : $this->db->escapeString(round($matches4['size'])) + ), + $this->db->escapeString($matches4['category']), + $this->functions->from_unixtime(strtotime($matches4['date'])), + $this->db->escapeString('prelist'), + $md5, + $this->db->escapeString($matches4['files']), + ($nuked === '' ? IRCScraper::NO_NUKE : $nuked), + ($nukereason === '' ? 'NULL' : $this->db->escapeString($nukereason))))) { + $newNames++; + } + } + } + } + } + } elseif ($this->echooutput) { + echo $this->c->error("Update from Prelist failed."); + } + return $newNames; + } + + /** + * Get new pre from this source. + * @return int + */ + protected function retrieveOrlydb() + { + $newNames = 0; + $buffer = $this->getUrl('http://www.orlydb.com/'); + if ($buffer !== false) { + $matches = $matches2 = $match = array(); + if (preg_match('/<div id="releases">(.+)<div id="pager">/s', $buffer, $match)) { + if (preg_match_all('/<div>.+?<\/div>/s', $match["1"], $matches)) { + foreach ($matches as $m1) { + foreach ($m1 as $m) { + if (preg_match('/timestamp">(?P<date>.+?)<\/span>.+?section">.+?">(?P<category>.+?)<\/a>.+?release">(?P<title>.+?)<\/span>(.+info">(?P<size>.+?) \| (?P<files>\d+F))?/s', $m, $matches2)) { + + // Skip if too short. + if (strlen($matches2['title']) < 15) { continue; - } else { - if (!isset($matches2["size"]) && empty($matches2["size"])) { - $size = "NULL"; - } else { - $size = $db->escapeString($matches2["size"]); - } - if (strlen($matches2['title']) > 15) { - if($db->exec(sprintf("INSERT INTO prehash (title, size, category, predate, source, md5) VALUES (%s, %s, %s, FROM_UNIXTIME(".strtotime($matches2["date"])."), %s, %s)", $db->escapeString($matches2["title"]), $size, $db->escapeString($matches2["category"]), $db->escapeString("orlydb"), $md5)));{ - $newnames++; - } + } + $md5 = $this->db->escapeString(md5($matches2['title'])); + $oldName = $this->db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); + if ($oldName !== false) { + continue; + } elseif ($this->db->exec( + sprintf(' + INSERT INTO prehash (title, size, category, predate, source, md5, files) + VALUES (%s, %s, %s, %s, %s, %s)', + $this->db->escapeString($matches2['title']), + ((!isset($matches2['size']) && empty($matches2['size'])) + ? 'NULL' + : $this->db->escapeString($matches2['size']) + ), + $this->db->escapeString($matches2['category']), + $this->functions->from_unixtime(strtotime($matches2['date'])), + $this->db->escapeString('orlydb'), + $md5, + ((!isset($matches2['files']) && empty($matches2['files'])) + ? 'NULL' + : $this->db->escapeString($matches2['files'])) + )) + ) { + $newNames++; } } } } } } + } else { + if ($this->echooutput) { + echo $this->c->error("Update from Orly failed."); + } } - } - else - { - echo $this->c->error("Update from Orly failed."); - } - return $newnames; + return $newNames; } - public function retrieveSrr() + /** + * Get pre from this source. + * @return int + */ + protected function retrieveSrr() { - $db = new DB(); - $f = new Functions(); - $newnames = 0; - $url = "http://www.srrdb.com/feed/srrs"; + $newNames = 0; - $options = array( - 'http'=>array( - 'method'=>"GET", - 'header'=>"Accept-language: en\r\n" . - "Cookie: foo=bar\r\n" . // check function.stream-context-create on php.net - "User-Agent: Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.102011-10-16 20:23:10\r\n" // i.e. An iPad - ) - ); + $data = $this->getUrl("http://www.srrdb.com/feed/srrs"); - $context = stream_context_create($options); - $web = $this->fileContents($url, false, $context); - if ($web !== false) - { - $releases = simplexml_load_string($this->fileContents($url, false, $context)); - if ($releases !== false) - { + if ($data !== false) { + $releases = @simplexml_load_string($data); + if ($releases !== false) { + foreach ($releases->channel->item as $release) { - foreach ($releases->channel->item as $release) - { - $md5 = $db->escapeString(md5($release->title)); - $oldname = $db->queryOneRow(sprintf('SELECT md5 FROM prehash WHERE md5 = %s', $md5)); - if ($oldname !== false) { - continue; - } else { - if (strlen($release->title) > 15) { - if($db->exec(sprintf('INSERT INTO prehash (title, predate, source, md5) VALUES (%s, %s, %s, %s)', $db->escapeString($release->title), $f->from_unixtime(strtotime($release->pubDate)), $db->escapeString('srrdb'),$md5)));{$newnames++; -} - } - } - } - } else { + // If it's too short, skip. + if (strlen($release->title) < 15) { + continue; + } + $md5 = $this->db->escapeString(md5($release->title)); + $oldName = $this->db->queryOneRow(sprintf('SELECT ID, nfo FROM prehash WHERE md5 = %s', $md5)); + + $nfo = $size = ''; + if (preg_match('/<dt>NFO availability<\/dt>\s*<dd>(?P<nfo>(yes|no))<\/dd>/is', $release->description, $description)) { + $nfo = ($description['nfo'] === 'yes' ? $this->db->escapeString('srrdb') : 'NULL'); + } + + if (preg_match('/Filesize.*<td>(?P<size>\d*)<\/td>\s*<td>.*?<\/td>\s*<td>.*?<\/td>\s*<\/tr>\s*<\/table>\s*/is', $release->description, $description)) { + $size = ((isset($description['size']) && !empty($description['size'])) ? $this->db->escapeString(bytesToSizeString($description['size'])) : 'NULL'); + } + + if ($oldName !== false) { + if ($nfo !== '' && empty($oldName['nfo'])) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET size = %s, predate = %s, source = %s, nfo = %s + WHERE ID = %d', + $size, + $this->functions->from_unixtime(strtotime($release->pubDate)), + $this->db->escapeString('srrdb'), + $nfo, + $oldName['ID'] + ) + ); + } + continue; + } else if ($this->db->exec( + sprintf(' + INSERT INTO prehash (title, predate, source, md5, nfo, size) + VALUES (%s, %s, %s, %s, %s, %s)', + $this->db->escapeString($release->title), + $this->functions->from_unixtime(strtotime($release->pubDate)), + $this->db->escapeString('srrdb'), + $md5, + $nfo, + $size))) { + $newNames++; + } + } + } elseif ($this->echooutput) { echo $this->c->error("Update from Srr failed."); } - } else { + } elseif ($this->echooutput) { echo $this->c->error("Update from Srr failed."); } - return $newnames; + return $newNames; } public function retrievePredbme() { $db = new DB(); $f = new Functions(); - $newnames = $updated = 0; + $newNames = $updated = 0; $options = array( 'http' => array( @@ -537,7 +586,7 @@ Class PreHash { if (strlen($release->title) > 15) { if($db->exec(sprintf("INSERT INTO prehash (title, predate, source, md5) VALUES (%s, now(), %s, %s)", $db->escapeString($release->title), $db->escapeString("predbme"), $md5)));{ - $newnames++; + $newNames++; } } } @@ -547,236 +596,387 @@ Class PreHash echo $this->c->error("Update from Predbme failed."); } } - return $newnames; + return $newNames; } - public function retrieveAllfilledMoovee() + /** + * Get pre from this source. + * + * @return int + */ + protected function retrieveAllfilledMoovee() { - $db = new DB(); - $functions = new Functions(); - $newnames = $updated = 0; - $groups = new Groups(); - $groupID = $functions->getIDByName('alt.binaries.moovee'); - $buffer = $this->fileContents('http://abmoovee.allfilled.com/reqs.php?fetch=posted&page=1'); - if ($buffer !== false && strlen($buffer)) - { - if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) - { - foreach ($matches as $match) - { - foreach ($match as $m) - { - if (preg_match('/<td class="cell_reqid">(?P<requestID>\d+)<\/td>.+<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})<\/td>/s', $m, $matches2)) - { - if (isset($matches2["requestID"]) && isset($matches2["title"])) - { - $title = $db->escapeString($matches2["title"]); - $md5 = $db->escapeString(md5($matches2["title"])); - if (strlen($title) > 15) { - $dupeCheck = $db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); - if ($dupeCheck === false) { - $db->exec(sprintf("INSERT INTO prehash (title, predate, source, md5, requestID, groupID, category) VALUES (%s, %s, %s, %s, %s, %d, 'Movies')", $title, $db->escapeString($matches2["predate"]), $db->escapeString('abMooVee'), $md5, $matches2["requestID"], $groupID)); - $newnames++; - } else { - $db->exec(sprintf('UPDATE prehash SET requestID = %s, groupID = %d WHERE md5 = %s', $matches2["requestID"], $groupID, $md5)); - } - } + $newNames = 0; + $groupid = $this->db->queryOneRow("SELECT ID FROM groups WHERE name = 'alt.binaries.moovee'"); + + if ($groupid === false) { + return 0; + } else { + $groupid = $groupid['ID']; + } + + $buffer = $this->getUrl('http://abmoovee.allfilled.com/reqs.php?fetch=posted&page=1'); + if ($buffer !== false) { + $matches = $matches2 = $match = array(); + if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) { + foreach ($matches as $match) { + foreach ($match as $m) { + if (preg_match('/<td class="cell_reqid">(?P<requestid>\d+)<\/td>.+?<td class="cell_filecount">(?P<files>\d+x\d+)<\/td>.+?<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})<\/td>/s', $m, $matches2)) { + if (isset($matches2["requestID"]) && isset($matches2["title"])) { + + // If too short, skip. + if (strlen($matches2["title"]) < 15) { + continue; + } + $md5 = $this->db->escapeString(md5($matches2["title"])); + + $dupeCheck = $this->db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); + if ($dupeCheck === false) { + $this->db->exec( + sprintf(" + INSERT INTO prehash (title, predate, source, md5, requestID, groupID, files, category) + VALUES (%s, %s, %s, %s, %s, %d, %s, 'Movies')", + $this->db->escapeString($matches2["title"]), + $this->db->from_unixtime(strtotime($matches2["predate"])), + $this->db->escapeString('abMooVee'), + $md5, + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2['files']) + ) + ); + $newNames++; + } else if (empty($dupeCheck['requestID'])) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET requestID = %s, groupID = %d, files = %s + WHERE md5 = %s', + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2['files']), + $md5 + ) + ); + } } } - } - } - } - - else - echo $this->c->error ("Error: Update from Moovee failed."); - } - return $newnames; -} - - public function retrieveAllfilledTeevee() - { - $db = new DB(); - $functions = new Functions(); - $newnames = $updated = 0; - $groups = new Groups(); - $groupID = $functions->getIDByName('alt.binaries.teevee'); - $buffer = $this->fileContents('http://abteevee.allfilled.com/reqs.php?fetch=posted&page=1'); - if ($buffer !== false && strlen($buffer)) - { - if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) - { - foreach ($matches as $match) - { - foreach ($match as $m) - { - if (preg_match('/<td class="cell_reqid">(?P<requestID>\d+)<\/td>.+<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})<\/td>/s', $m, $matches2)) - { - if (isset($matches2["requestID"]) && isset($matches2["title"])) - { - $title = $db->escapeString($matches2["title"]); - $md5 = $db->escapeString(md5($matches2["title"])); - if (strlen($title) > 15) { - $dupeCheck = $db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); - if ($dupeCheck === false) { - $db->exec(sprintf("INSERT INTO prehash (title, predate, source, md5, requestID, groupID, category) VALUES (%s, %s, %s, %s, %s, %d, 'TV')", $title, $db->escapeString($matches2["predate"]), $db->escapeString('abTeeVee'), $md5, $matches2["requestID"], $groupID)); - $newnames++; - } else { - $db->exec(sprintf('UPDATE prehash SET requestID = %s, groupID = %d WHERE md5 = %s', $matches2["requestID"], $groupID, $md5)); - } - } - } - } - } - } - } else - echo $this->c->error ("Error: Update from Teevee failed."); - } - return $newnames; - } - - public function retrieveAllfilledErotica() - { - $db = new DB(); - $functions = new Functions(); - $newnames = $updated = 0; - $groups = new Groups(); - $groupID = $functions->getIDByName('alt.binaries.erotica'); - $buffer = $this->fileContents('http://aberotica.allfilled.com/reqs.php?fetch=posted&page=1'); - if ($buffer !== false && strlen($buffer)) - { - if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) - { - foreach ($matches as $match) - { - foreach ($match as $m) - { - if (preg_match('/<td class="cell_reqid">(?P<requestID>\d+)<\/td>.+<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})<\/td>/s', $m, $matches2)) - { - if (isset($matches2["requestID"]) && isset($matches2["title"])) - { - $title = $db->escapeString($matches2["title"]); - $md5 = $db->escapeString(md5($matches2["title"])); - if (strlen($title) > 15) { - $dupeCheck = $db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); - if ($dupeCheck === false) { - $db->exec(sprintf("INSERT INTO prehash (title, predate, source, md5, requestid, groupid, category) VALUES (%s, %s, %s, %s, %s, %d, 'XXX')", $title, $db->escapeString($matches2["predate"]), $db->escapeString('abErotica'), $md5, $matches2["requestID"], $groupID)); - $newnames++; - } else { - $db->exec(sprintf('UPDATE prehash SET requestID = %s, groupID = %d WHERE md5 = %s', $matches2["requestID"], $groupID, $md5)); - } - } - } - } - } - } - } else - echo $this->c->error ("Error: Update from Erotica failed."); - } - return $newnames; -} - - public function retrieveAllfilledForeign() - { - $db = new DB(); - $functions = new Functions(); - $newnames = $updated = 0; - $groups = new Groups(); - $groupID = $functions->getIDByName('alt.binaries.mom'); - $buffer = $this->fileContents('http://abforeign.allfilled.com/reqs.php?fetch=posted&page=1'); - if ($buffer !== false && strlen($buffer)) - { - if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) - { - foreach ($matches as $match) - { - foreach ($match as $m) - { - if (preg_match('/<td class="cell_reqid">(?P<requestID>\d+)<\/td>.+<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?)<\/td>/s', $m, $matches2)) - { - if (isset($matches2["requestID"]) && isset($matches2["title"])) - { - $title = $db->escapeString($matches2["title"]); - $md5 = $db->escapeString(md5($matches2["title"])); - if (strlen($title) > 15) { - $dupeCheck = $db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); - if ($dupeCheck === false) { - if($db->exec(sprintf("INSERT INTO prehash (title, predate, source, md5, requestid, groupid) VALUES (%s, %s, %s, %s, %s, %d)", $title, $db->escapeString($matches2["predate"]), $db->escapeString('abForeign'), $md5, $matches2["requestID"], $groupID))); - $newnames++; - } else { - $db->exec(sprintf('UPDATE prehash SET requestID = %s, groupID = %d WHERE md5 = %s', $matches2["requestID"], $groupID, $md5)); - } - } - } - } - } - } - } else - echo $this->c->error ("Error: Update from Foreign failed."); - } - return $newnames; -} - - public function retrieveAbgx() - { - $db = new DB(); - $newnames = 0; - $db = new DB(); - $functions = new Functions(); - $groups = new Groups(); - - $options = array( - 'http'=>array( - 'method'=>"GET", - 'header'=>"Accept-language: en\r\n" . - "Cookie: foo=bar\r\n" . // check function.stream-context-create on php.net - "User-Agent: Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.102011-10-16 20:23:10\r\n" // i.e. An iPad - ) - ); - $context = stream_context_create($options); - $arr = array('x360', 'abcp', 'abgw', 'abgwu', 'absp', 'abgn', 'spsv', 'n3ds', 'abgx', 'abg', 'x360'); - foreach ($arr as &$value) - { - $releases = simplexml_load_string($this->fileContents('http://www.abgx.net/rss/' . $value . '/posted.rss', false, $context)); - if ($releases !== false) - { - preg_match('/^Filled requests in #(\S+)/', $releases->channel->description, $groupname); - $groupID = ($functions->getIDByName($groupname[1])) ? $functions->getIDByName($groupname[1]) : 0; - foreach ($releases->channel->item as $release) - { - preg_match('/^Req (\d+) - (\S+) .+/', $release->title, $request); - $requestID = $request[1]; - preg_match('/\(\d+\) (\S+) .+(\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2})/', $release->description, $title); - $md5 = md5($title[1]); - $predate = $title[2]; - - $oldname = $db->queryOneRow(sprintf('SELECT md5, requestID, groupID FROM prehash WHERE md5 = %s', $db->escapeString($md5))); - if ($oldname !== false) - { - $db->exec(sprintf('UPDATE prehash SET requestID = %d, groupID = %d WHERE md5 = %s', max($oldname['requestID'], $requestID), max($oldname['groupID'], $groupID), $db->escapeString($md5))); - } - else - { - if (strlen($title[1]) > 15) { - if ($db->exec(sprintf('INSERT INTO prehash (title, predate, source, md5, requestID, groupID) VALUES (%s, %s, %s, %s, %d, %d)', $db->escapeString($title[1]), $functions->from_unixtime(strtotime($predate)), $db->escapeString('abgx'), $db->escapeString($md5), $requestID, $groupID))) - { - $newnames++; - } - } } } } - else - echo $this->c->error ("Error: Update from ABGX failed."); + } elseif ($this->echooutput) { + echo $this->c->error("Update from Moovee failed."); + } + return $newNames; + } + + /** + * Get new pre for this source. + * + * @return int + */ + protected function retrieveAllfilledTeevee() + { + $newNames = 0; + $groupid = $this->db->queryOneRow("SELECT ID FROM groups WHERE name = 'alt.binaries.teevee'"); + + if ($groupid === false) { + return 0; + } else { + $groupid = $groupid['ID']; + } + + $buffer = $this->getUrl('http://abteevee.allfilled.com/reqs.php?fetch=posted&page=1'); + if ($buffer !== false) { + $matches = $matches2 = $match = array(); + if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) { + foreach ($matches as $match) { + foreach ($match as $m) { + if (preg_match('/<td class="cell_reqid">(?P<requestID>\d+)<\/td>.+?<td class="cell_filecount">(?P<files>\d+x\d+)<\/td>.+?<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})<\/td>/s', $m, $matches2)) { + if (isset($matches2["requestID"]) && isset($matches2["title"])) { + + // Skip if too short. + if (strlen($matches2["title"]) < 15) { + continue; + } + $md5 = $this->db->escapeString(md5($matches2["title"])); + $dupeCheck = $this->db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); + if ($dupeCheck === false) { + $this->db->exec( + sprintf(" + INSERT INTO prehash (title, predate, source, md5, requestID, groupID, files, category) + VALUES (%s, %s, %s, %s, %s, %d, %s, 'TV')", + $this->db->escapeString($matches2["title"]), + $this->db->from_unixtime(strtotime($matches2["predate"])), + $this->db->escapeString('abTeeVee'), + $md5, + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2['files']) + ) + ); + $newNames++; + } else if (empty($dupeCheck['requestID'])) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET requestID = %s, groupID = %d, files = %s + WHERE md5 = %s', + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2['files']), + $md5 + ) + ); + } + } + } + } + } + } + } elseif ($this->echooutput) { + echo $this->c->error("Update from Teevee failed."); + } + return $newNames; + } + + /** + * Get new pre for this source. + * + * @return int + */ + protected function retrieveAllfilledErotica() + { + $newNames = 0; + $groupid = $this->db->queryOneRow("SELECT ID FROM groups WHERE name = 'alt.binaries.erotica'"); + + if ($groupid === false) { + return 0; + } else { + $groupid = $groupid['ID']; + } + + $buffer = $this->getUrl('http://aberotica.allfilled.com/reqs.php?fetch=posted&page=1'); + if ($buffer !== false) { + $matches = $matches2 = $match = array(); + if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) { + foreach ($matches as $match) { + foreach ($match as $m) { + if (preg_match('/<td class="cell_reqid">(?P<requestid>\d+)<\/td>.+?<td class="cell_type">(?P<category>.+?)<\/td>.+?<td class="cell_filecount">(?P<files>\d+x\d+)<\/td>.+?<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})<\/td>/s', $m, $matches2)) { + if (isset($matches2["requestID"]) && isset($matches2["title"])) { + + // If too short, skip. + if (strlen($matches2["title"]) < 15) { + continue; + } + $md5 = $this->db->escapeString(md5($matches2["title"])); + + $dupeCheck = $this->db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); + if ($dupeCheck === false) { + $this->db->exec( + sprintf(" + INSERT INTO prehash (title, predate, source, md5, requestID, groupID, files, category) + VALUES (%s, %s, %s, %s, %s, %d, %s, %s)", + $this->db->escapeString($matches2["title"]), + $this->db->from_unixtime(strtotime($matches2["predate"])), + $this->db->escapeString('abErotica'), + $md5, + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2['files']), + $this->db->escapeString('XXX-' . $matches2['category']) + ) + ); + $newNames++; + } else if (empty($dupeCheck['requestID'])) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET requestID = %s, groupID = %d, files = %s + WHERE md5 = %s', + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2['files']), + $md5 + ) + ); + } + } + } + } + } + } + } elseif ($this->echooutput) { + echo $this->c->error("Update from Erotica failed."); + } + return $newNames; + } + + /** + * Get new pre for this source. + * + * @return int + */ + protected function retrieveAllfilledForeign() + { + $newNames = 0; + $groupid = $this->db->queryOneRow("SELECT ID FROM groups WHERE name = 'alt.binaries.mom'"); + + if ($groupid === false) { + return 0; + } else { + $groupid = $groupid['ID']; + } + + $buffer = $this->getUrl('http://abforeign.allfilled.com/reqs.php?fetch=posted&page=1'); + if ($buffer !== false) { + if (preg_match_all('/<tr class="(even|odd)".+?<\/tr>/s', $buffer, $matches)) { + $matches = $matches2 = $match = array(); + foreach ($matches as $match) { + foreach ($match as $m) { + if (preg_match('/<td class="cell_reqid">(?P<requestid>\d+)<\/td>.+<td class="cell_type">(?P<category>.+?)<\/td>.+?<td class="cell_filecount">(?P<files>\d+x\d+)<\/td>.+?<td class="cell_request">(?P<title>.+)<\/td>.+<td class="cell_statuschange">(?P<predate>\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?)<\/td>/s', $m, $matches2)) { + if (isset($matches2["requestID"]) && isset($matches2["title"])) { + + // If too short, skip. + if (strlen($matches2["title"]) < 15) { + continue; + } + $md5 = $this->db->escapeString(md5($matches2["title"])); + + $dupeCheck = $this->db->queryOneRow(sprintf('SELECT ID, requestID FROM prehash WHERE md5 = %s', $md5)); + if ($dupeCheck === false) { + $this->db->exec( + sprintf(" + INSERT INTO prehash (title, predate, source, md5, requestID, groupID, files, category) + VALUES (%s, %s, %s, %s, %s, %d, %s, %s)", + $this->db->escapeString($matches2["title"]), + $this->db->from_unixtime(strtotime($matches2["predate"])), + $this->db->escapeString('abForeign'), + $md5, + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2["files"]), + $this->db->escapeString($matches2["category"]) + ) + ); + $newNames++; + } else if (empty($dupeCheck['requestID'])) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET requestID = %s, groupID = %d, files = %s, category = %s + WHERE md5 = %s', + $matches2["requestID"], + $groupid, + $this->db->escapeString($matches2["files"]), + $this->db->escapeString($matches2["category"]), + $md5 + ) + ); + } + } + } + } + } + } + } elseif ($this->echooutput) { + echo $this->c->error("Update from Foreign failed."); + } + return $newNames; + } + + /** + * Get new pre for this source. + * + * @return int + */ + protected function retrieveAbgx() + { + $newnames = 0; + $groups = new Groups(); + $groupname = $request = $title = ''; + + + $arr = array('x360', 'abcp', 'abgw', 'abgwu', 'absp', 'abgn', 'spsv', 'n3ds', 'abgx', 'abg', 'x360'); + foreach ($arr as &$value) { + $data = $this->getUrl('http://www.abgx.net/rss/' . $value . '/posted.rss'); + if ($data !== false) { + $releases = @simplexml_load_string($data); + if ($releases !== false) { + preg_match('/^Filled requests in #(\S+)/', $releases->channel->description, $groupname); + $groupid = ($groups->getIDByName($groupname[1])) ? $groups->getIDByName($groupname[1]) : 0; + foreach ($releases->channel->item as $release) { + + preg_match('/\(\d+\) (\S+) .+(\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2})/', $release->description, $title); + // Skip if too short. + if (strlen($title[1]) < 15) { + continue; + } + preg_match('/^Req (\d+) - (\S+) .+/', $release->title, $request); + $requestid = $request[1]; + $md5 = md5($title[1]); + $predate = $title[2]; + + $oldname = $this->db->queryOneRow(sprintf('SELECT md5, requestID, groupID FROM prehash WHERE md5 = %s', $this->db->escapeString($md5))); + if ($oldname !== false && empty($oldname['requestID'])) { + $this->db->exec( + sprintf(' + UPDATE prehash + SET requestID = %d, groupID = %d + WHERE md5 = %s', + max($oldname['requestID'], $requestid), + max($oldname['groupID'], $groupid), + $this->db->escapeString($md5) + ) + ); + } + else if ($oldname === false) { + if ($this->db->exec( + sprintf(' + INSERT INTO prehash (title, predate, source, md5, requestID, groupID) + VALUES (%s, %s, %s, %s, %d, %d)', + $this->db->escapeString($title[1]), + $this->db->from_unixtime(strtotime($predate)), + $this->db->escapeString('abgx'), + $this->db->escapeString($md5), + $requestid, + $groupid))) { + $newnames++; + } + } + } + } else { + if ($this->echooutput) { + echo $this->c->error("Update from ABGX failed."); + } + return $newnames; + } + } else { + if ($this->echooutput) { + echo $this->c->error("Update from ABGX failed."); + } + return $newnames; + } } return $newnames; } - public function retrieveUsenetCrawler() + /** + * Get new pre for this source. + * + * @return int + */ + protected function retrieveUsenetCrawler() { $db = new DB(); $newnames = 0; - $functions = new Functions(); - $html = str_get_html($this->getWebPage("http://www.usenet-crawler.com/predb?q=&c=&offset=0#results")); + + $data = $this->getUrl("http://www.usenet-crawler.com/predb?q=&c=&offset=0#results"); + if ($data === false) { + return 0; + } + + $html = str_get_html($data); $releases = @$html->find('table[id="browsetable"]'); if (!isset($releases[0])) { return $newnames; @@ -802,13 +1002,20 @@ Class PreHash } else { $title = trim($data[1]->innertext); } + + $md5 = md5($title); + // Check DB if we already have it. + $check = $db->queryOneRow(sprintf('SELECT ID FROM prehash WHERE md5 = %s', $db->escapeString($md5))); + if ($check !== false) { + continue; + } + $e = $data[2]->find('a'); $category = $e[0]->innertext; preg_match('/([\d\.]+MB)/', $data[3]->innertext, $match); $size = isset($match[1]) ? $match[1] : 'NULL'; - $md5 = md5($title); if (strlen($title) > 15 && $category != 'NUKED') { - if ($db->exec(sprintf('INSERT INTO prehash (title, predate, source, md5, category, size) VALUES (%s, %s, %s, %s, %s, %s)', $db->escapeString($title), $functions->from_unixtime($predate), $db->escapeString('usenet-crawler'), $db->escapeString($md5), $db->escapeString($category), $db->escapeString($size)))) { + if ($db->exec(sprintf('INSERT INTO prehash (title, predate, source, md5, category, size) VALUES (%s, %s, %s, %s, %s, %s)', $db->escapeString($title), $this->functions->from_unixtime($predate), $db->escapeString('usenet-crawler'), $db->escapeString($md5), $db->escapeString($category), $db->escapeString($size)))) { $newnames++; } } @@ -867,7 +1074,7 @@ Class PreHash if($this->echooutput) echo $this->c->header ("Matching up prehash NFOs with releases missing an NFO."); - $res = $db->query("SELECT r.ID, p.nfo, r.completion, r.guid, r.groupID FROM releases r INNER JOIN prehash p ON r.prehashID = p.ID WHERE r.nfostatus = 0 AND p.nfo IS NOT NULL LIMIT 100"); + $res = $db->query("SELECT r.ID, p.nfo, p.title, r.completion, r.guid, r.groupID FROM releases r INNER JOIN prehash p ON r.prehashID = p.ID WHERE r.nfostatus != 1 AND p.nfo IS NOT NULL LIMIT 100"); $total = count($res); if($total > 0) { @@ -876,10 +1083,21 @@ Class PreHash $functions = new Functions($this->echooutput); foreach ($res as $row) { - $buffer = getUrl($row["nfo"]); - if ($buffer !== false) - { - if ($functions->addAlternateNfo($db, $buffer, $row, $nntp)) + $URL = $row['nfo']; + + // To save space in the DB we do this instead of storing the full URL. + if ($URL === 'srrdb') { + $srrdb = urlencode($row['title']); + $URL = 'http://www.srrdb.com/download/file/' . $srrdb . '/' . $srrdb . '.nfo'; + } + + $buffer = $this->getUrl($URL); + + if ($buffer !== false) { + if (strlen($buffer) < 5) { + continue; + } + if ($this->functions->addAlternateNfo($db, $buffer, $row, $nntp)) { if($this->echooutput) echo '+'; @@ -1026,4 +1244,23 @@ Class PreHash return $str; } } + /** + * Get data from URL. + * + * @param string $url + * + * @return bool|string + */ + protected function getUrl($url) + { + return getUrl( + $url, + 'get', + '', + 'en', + false, + 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) ' . + 'Version/4.0.4 Mobile/7B334b Safari/531.21.102011-10-16 20:23:10', 'foo=bar' + ); + } }