Teknik is a suite of services with attractive and functional interfaces. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2939 lines
86 KiB

<?php
/**
* $Id: SmartIRC.php 302734 2010-08-24 01:17:01Z clockwerx $
* $Revision: 302734 $
* $Author: clockwerx $
* $Date: 2010-08-24 10:47:01 +0930 (Tue, 24 Aug 2010) $
*
* Net_SmartIRC
* This is a PHP class for communication with IRC networks,
* which conforms to the RFC 2812 (IRC protocol).
* It's an API that handles all IRC protocol messages.
* This class is designed for creating IRC bots, chats and show irc related info on webpages.
*
* Documenation, a HOWTO and examples are in SmartIRC included.
*
* Here you will find a service bot which I am also developing
* <http://cvs.meebey.net/atbs> and <http://cvs.meebey.net/phpbitch>
* Latest versions of Net_SmartIRC you will find on the project homepage
* or get it through PEAR since SmartIRC is an official PEAR package.
* See <http://pear.php.net/Net_SmartIRC>.
*
* Official Project Homepage: <http://sf.net/projects/phpsmartirc>
*
* Net_SmartIRC conforms to RFC 2812 (Internet Relay Chat: Client Protocol)
*
* Copyright (c) 2002-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
*
* Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// ------- PHP code ----------
require_once 'SmartIRC/defines.php';
define('SMARTIRC_VERSION', '1.1.0-dev ($Revision: 302734 $)');
define('SMARTIRC_VERSIONSTRING', 'Net_SmartIRC '.SMARTIRC_VERSION);
/**
* main SmartIRC class
*
* @package Net_SmartIRC
* @version 0.6.0-dev
* @author Mirco 'meebey' Bauer <mail@meebey.net>
* @access public
*/
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 $_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 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 privat
*/
var $_modulepath = '';
/**
* Stores all objects of the modules.
*
* @var string
* @access privat
*/
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. Initiales the messagebuffer and "links" the replycodes from
* global into properties. Also some PHP runtime settings are configured.
*
* @access public
* @return void
*/
function Net_SmartIRC_base()
{
// 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 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;
ingore_user_abort(true);
} 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 '<pre>'.htmlentities($formatedentry).'</pre>';
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:
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);
$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);
if (($this->_autoretry == true) &&
($this->_autoretrycount < $this->_autoretrymax)) {
$this->_delayReconnect();
$this->_autoretrycount++;
$this->reconnect();
} else {
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);
}
// </IRC methods>
/**
* 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 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 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();