From 2fc188127c22aa8113d0ac5ad1b2f91aa7fabeba Mon Sep 17 00:00:00 2001 From: Belliere Ludovic Date: Wed, 18 Jun 2008 11:18:18 +0200 Subject: [PATCH] dev save point --- sources/Event.php | 8 + sources/IRCMain.php | 123 +++++++++++ sources/IRCMain/Adapter.php | 512 +++++++++++++++++++------------------------- sources/IRCMain/Ctcp.php | 82 +++++++ 4 files changed, 436 insertions(+), 289 deletions(-) rewrite sources/IRCMain/Adapter.php (75%) create mode 100644 sources/IRCMain/Ctcp.php diff --git a/sources/Event.php b/sources/Event.php index d8fd723..4e47f34 100644 --- a/sources/Event.php +++ b/sources/Event.php @@ -172,6 +172,14 @@ class Event { } return true; } + + public function isCtcp() { + if ($this->data['message'][0] == chr(001)) { + return true; + } else { + return false; + } + } } ?> \ No newline at end of file diff --git a/sources/IRCMain.php b/sources/IRCMain.php index fa609eb..ade0384 100644 --- a/sources/IRCMain.php +++ b/sources/IRCMain.php @@ -3,7 +3,130 @@ require_once 'sources/IRCMain/Adapter.php'; class IRCMain extends IRCMain_Adapter { + + public function launch() { + parent::launch(); + + try { + $this->lastData = mktime(); + + $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($this->_socket === false) { + throw new Exception('Impossible de créer le socket IRC !',0); + } + + if (self::$ip != "") { + socket_bind($this->_socket, self::getConfig('ip')); + } + + $socketUp = socket_connect($this->_socket, self::getConfig('server'), self::getConfig('port')); + if ($socketUp===false) { + throw new Exception('Impossible de se connecter au server IRC ! ('.socket_last_error().')' ,0); + } + + $this->connected = true; + + if (self::$connection_password !== false) { + $this->put('PASS '.self::getConfig('password')); + } + // TODO : be sure for the validity of the connection password (what chain server return if fail ?) + + $this->put('USER '.self::getConfig('nick').' '.self::getConfig('nick').'@'.self::getConfig('ip').' '.self::getConfig('server').' :'.self::getConfig('nick')); + $this->put('NICK '.self::getConfig('nick')); + + /*$this->tick->setTick('all5sec',5); + $this->tick->addJob('all5sec','hello chan','privmsg',array(self::$channel,"I'm a tick. I show this msg all 5sec."),0,$this); + */ + + // Into the while ! + while (1) { + + // current data + $this->incomingData = $this->getIncomingData(); + + if (!is_array($this->incomingData)) { + $this->incomingData = array($this->incomingData); + } + + foreach ($this->incomingData as $data) { + if (!empty($data)) { + $event = $this->event()->setIncoming($data); + + $action = $event->getAction(); + + switch ($action) { + case Event::ACT_DISCONNECT: + $this->disconnect('ERROR: Closing Link'); + sleep(3); + throw new Exception('Closing Link.',1); + break; + case Event::ACT_PING: + $pong = split(':',$data); + $this->put('PONG '.$pong[1]); + echo "PING :{$pong[1]}\nPONG {$pong[1]}\n\n"; + break; + case Event::ACT_KICK: + sleep(1); + $this->joinChannel(self::getConfig('channel')); + break; + } + + $this->dataInformation = $dataInformation = $event->getData(); + + switch ($dataInformation['type']) { + + case Plugins_Command_Abstract::EVENT_PRIVMSG: + + // ctcp + if ($event->isCtcp()) { + + $ctcp = new IRCMain_Ctcp($action,$this); + $responce = $ctcp->getResponce(); + + self::notice($event->getDataSendBy(),$this->ctcp($responce)); + + } else { + $dataInformation['message'] = trim($dataInformation['message']); + if ($dataInformation['to'] == self::$botName) { + // auth proccess + // TODO : create a better login process + if (preg_match('`^connect ([^ ]+) ([^ ]+)`',$dataInformation['message'],$m)) { + if ($m[1] == 'admin' && $m[2] == 'mypass') { + $this->auth = true; + self::notice($event->getDataSendBy(),'Vous êtes bien authentifié comme administrateur.'); + } else { + self::notice($event->getDataSendBy(),'Erreur dans votre login et / ou mot de passe.'); + echo debug() ? 'l: '.$m[1].' p: '.$m[2]."\n":''; + } + continue; + } + } + } + break; + case 'NOTICE': + break; + } + self::$plugins->set_event($event); + } + } + } + } catch (myRuntimeException $e) { + $x = $e->getMessage(); + echo $x; + $x.= backtrace($e->getTrace()); + file_put_contents('errorlog',$x); + //if ($e->_level < 2 || ($e->_level >= 256 && $e->_level < 1024)) { + echo 'Error level : '.$e->_level."\n\n"; + throw new Exception('Error occured',0); + /*} else { + echo 'Error level : '.$e->_level."\n\n\n\n"; + throw new Exception("Error occured. Please see errorlog for details.",1); + }*/ + } catch (Exception $e) { + throw $e; + } + } } ?> \ No newline at end of file diff --git a/sources/IRCMain/Adapter.php b/sources/IRCMain/Adapter.php dissimilarity index 75% index 7c4adce..caacda7 100644 --- a/sources/IRCMain/Adapter.php +++ b/sources/IRCMain/Adapter.php @@ -1,289 +1,223 @@ - '1.0', - 'server' => 'localhost', - 'port' => 6667, - 'channel' => '#test', - 'nick' => 'irBot', - 'ip' => '', - 'domain' => '', - 'password' => false, - 'nickserv' => false, - ); - - public function getIncomingData() { - - $buffer = ''; - socket_set_nonblock($this->C); - - while (1) { - //echo "TOC - ",time(),"\n"; - $this->tick->doAllTicks(); - $buf = @socket_read($this->C, 4096); - - if (empty($buf)) { - $this->CheckTimeout(); - sleep(1); - continue; - } - - $this->lastData = mktime(); - - if (!strpos($buf, "\n")) { //Si ne contient aucun retour, on bufferise - $buffer = $buffer.$buf; - $data = ""; //rien è envoyer - } else { - //Si contient au moins un retour, - //on vèrifie que le dernier caractère en est un - if (substr($buf, -1, 1) == "\n") { - //alors on additionne ces donnèes au buffer - $data = $buffer.$buf; - $buffer = ""; //on vide le buffer - } else { - //si le dernier caractère n'est pas un retour è la - //ligne, alors on envoit tout jusqu'au dernier retour - //puis on bufferise le reste - $buffer = $buffer.substr($buf, strrchr($buf, "\n")); - $data = substr($buf, 0, strrchr($buf, "\n")); - $data = $buffer.$data; - $buffer = ""; //on vide le buffer - } - } - - if ($data != '') { - $data = split("\n", $data); - return $data; - } - - continue; - } - } - - public function launch() { - self::load_core_plugin(); - self::plugins()->Init(); - - try { - $this->lastData = mktime(); - - $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($this->_socket === false) { - throw new Exception('Impossible de créer le socket IRC !',0); - } - - if (self::$ip != "") { - socket_bind($this->_socket, self::getConfig('ip')); - } - - $socketUp = socket_connect($this->_socket, self::getConfig('server'), self::getConfig('port')); - if ($socketUp===false) { - throw new Exception('Impossible de se connecter au server IRC ! ('.socket_last_error().')' ,0); - } - - $this->connected = true; - - if (self::$connection_password !== false) { - $this->put('PASS '.self::getConfig('password')); - } - // TODO : be sure for the validity of the connection password (what chain server return if fail ?) - - $this->put('USER '.self::getConfig('nick').' '.self::getConfig('nick').'@'.self::getConfig('ip').' '.self::getConfig('server').' :'.self::getConfig('nick')); - $this->put('NICK '.self::getConfig('nick')); - - /*$this->tick->setTick('all5sec',5); - $this->tick->addJob('all5sec','hello chan','privmsg',array(self::$channel,"I'm a tick. I show this msg all 5sec."),0,$this); - */ - - // Into the while ! - while (1) { - - // current data - $this->incomingData = $this->getIncomingData(); - - if (!is_array($this->incomingData)) { - $this->incomingData = array($this->incomingData); - } - - foreach ($this->incomingData as $data) { - if (!empty($data)) { - $event = $this->event()->setIncoming($data); - - $action = $event->getAction(); - - switch ($action) { - case Event::ACT_DISCONNECT: - $this->disconnect('ERROR: Closing Link'); - sleep(3); - throw new Exception('Closing Link.',1); - break; - case Event::ACT_PING: - $pong = split(':',$data); - $this->put('PONG '.$pong[1]); - echo "PING :{$pong[1]}\nPONG {$pong[1]}\n\n"; - break; - case Event::ACT_KICK: - sleep(1); - $this->joinChannel(self::getConfig('channel')); - break; - } - - $this->dataInformation = $dataInformation = $event->getData(); - - switch ($dataInformation['type']) { - - case Plugins_Command_Abstract::EVENT_PRIVMSG: - - // ctcp - if ($dataInformation['message'][0] == chr(001)) { - - // we don't need this character - $dataInformation['message'] = str_replace(chr(001), "", $dataInformation['message']); - if (strstr($dataInformation['message'],' ') === true) { - list($cmd,$query) = explode(" ",$dataInformation['message']); - } else { - $cmd = $dataInformation['message']; - } - - // we don't need this character - //$cmd = str_replace(chr(001), "", $msg_info['message']); - $cmd = trim($cmd); - - switch ($cmd) { - case self::CTCP_CLIENTINFO: - self::notice($dataInformation['from'],$this->ctcp('PING VERSION TIME USERINFO CLIENTINFO')); - break; - - case self::CTCP_VERSION: - self::notice($dataInformation['from'],$this->ctcp('RPGBot version '.self::getConfig('version').' - PHP '.phpversion().' -- on http://irbot.irstat.org')); - break; - - case self::CTCP_USERINFO: - self::notice($dataInformation['from'],$this->ctcp('RPGBot')); - break; - - case self::CTCP_TIME: - self::notice($dataInformation['from'],$this->ctcp(date('Y-m-d H:i:s'))); - break; - - case self::CTCP_PING: - self::notice($dataInformation['from'],$this->ctcp("PING ".$query)); - break; - default: - self::notice($msg_info['from'],$this->ctcp("UNKNOWN CTCP REQUEST : '$cmd'")); - break; - } - } else { - $dataInformation['message'] = trim($dataInformation['message']); - if ($dataInformation['to'] == self::$botName) { - // auth proccess - // TODO : create a better login process - if (preg_match('`^connect ([^ ]+) ([^ ]+)`',$dataInformation['message'],$m)) { - if ($m[1] == 'admin' && $m[2] == 'mypass') { - $this->auth = true; - self::notice($dataInformation['from'],'Vous êtes bien authentifié comme administrateur.'); - } else { - self::notice($dataInformation['from'],'Erreur dans votre login et / ou mot de passe.'); - echo debug() ? 'l: '.$m[1].' p: '.$m[2]."\n":''; - } - continue; - } - } - } - break; - case 'NOTICE': - break; - } - self::$plugins->set_event($event); - } - } - } - } catch (myRuntimeException $e) { - $x = $e->getMessage(); - echo $x; - $x.= backtrace($e->getTrace()); - file_put_contents('errorlog',$x); - //if ($e->_level < 2 || ($e->_level >= 256 && $e->_level < 1024)) { - echo 'Error level : '.$e->_level."\n\n"; - throw new Exception('Error occured',0); - /*} else { - echo 'Error level : '.$e->_level."\n\n\n\n"; - throw new Exception("Error occured. Please see errorlog for details.",1); - }*/ - } catch (Exception $e) { - throw $e; - } - } - - static private function pluginsFactory() { - if (!self::$_pluginsInstance) { - self::$_pluginsInstance = new plugins($this); - } - return self::$_pluginsInstance; - } - - public function getConfig($name) { - return $this->_config[$name]; - } - - public function setConfig(array $options) { - foreach ($options as $option => $value) { - if ($option == 'botVersion') { - return false; - } - - $this->_config[$option] = $value; - } - return true; - } - - function colors($msg,$text,$background=false) { - $color_tag = chr(3); - $first = ($background)?$color_tag.$text.','.$background:$color_tag.$text; - return $first.$msg.$color_tag; - } - - function bold($msg) { - return chr(2).$msg.chr(2); - } - - function ctcp($msg) { - return chr(1).$msg.chr(1); - } - - function reverse_color($msg) { - return chr(22).$msg.chr(22); - } - - function underline($msg) { - return chr(31).$msg.chr(31); - } - - function paragraphe($msg) { - return explode("\n",$msg); - } - - public function getBotName() { - return self::getConfig('nick'); - } - -} - -?> \ No newline at end of file + '1.0', + 'server' => 'localhost', + 'port' => 6667, + 'channel' => '#test', + 'nick' => 'irBot', + 'ip' => '', + 'domain' => '', + 'password' => false, + 'nickserv' => false, + 'socketTimeout' => 180, + ); + + abstract function __construct(array $options); + + public function getIncomingData() { + + $buffer = ''; + socket_set_nonblock($this->C); + + while (1) { + //echo "TOC - ",time(),"\n"; + $this->tick->doAllTicks(); + $buf = @socket_read($this->_socket, 4096); + + if (empty($buf)) { + $this->_checkTimeout(); + sleep(1); + continue; + } + + $this->_lastTimeData = mktime(); + + if (!strpos($buf, "\n")) { //Si ne contient aucun retour, on bufferise + $buffer = $buffer.$buf; + $data = ""; //rien è envoyer + } else { + //Si contient au moins un retour, + //on vèrifie que le dernier caractère en est un + if (substr($buf, -1, 1) == "\n") { + //alors on additionne ces donnèes au buffer + $data = $buffer.$buf; + $buffer = ""; //on vide le buffer + } else { + //si le dernier caractère n'est pas un retour è la + //ligne, alors on envoit tout jusqu'au dernier retour + //puis on bufferise le reste + $buffer = $buffer.substr($buf, strrchr($buf, "\n")); + $data = substr($buf, 0, strrchr($buf, "\n")); + $data = $buffer.$data; + $buffer = ""; //on vide le buffer + } + } + + if ($data != '') { + $data = split("\n", $data); + return $data; + } + + continue; + } + } + + private function _checkTimeout() { + $now = mktime(); + if ($this->_lastTimeData+self::getConfig('socketTimeout') < mktime()) { + throw new Exception('Connection lost (Timeout).',1); + } + $lag = $now-$this->_lastTimeData; + if ( $lag > 20 && ($lag % 10) == 0) { + echo "Lag: ".$lag." seconds\n"; + } + } + + public function launch() { + $this->_pluginsInstance = new plugins(); + $this->_pluginsInstance->add_command('core','shownick',0,'Show the current nick used (debug)','mixed'); + $this->_pluginsInstance->add_command('core','nick',1,'Change the current nick','mixed'); + $this->_pluginsInstance->add_command('core','quit',0,'Disconnect and stop the process','mixed'); + $this->_pluginsInstance->add_command('core','restart',0,'Disconnect and restart the process','mixed'); + $this->_pluginsInstance->add_command('core','help',0,'Hmm, je dois recoder cette fonction','mixed'); + $this->_pluginsInstance->Init(); + $this->_lastTimeData = mktime(); + } + + public function getConfig($name) { + return $this->_config[$name]; + } + + public function setConfig(array $options) { + foreach ($options as $option => $value) { + if ($option == 'botVersion') { + return false; + } + + $this->_config[$option] = $value; + } + return true; + } + + public function joinChannel($channel) { + $this->put('JOIN '.$channel); + echo "Join channel $channel ...\n"; + } + + public function newNick($new=false) { + switch ($new) { + case self::getConfig('nick'): + echo "New nick : [ERR] no changes :". self::getConfig('nick') . ' == ' . $new ."\n"; + break; + case false: + self::setConfig(array( + 'nick' => self::getConfig('nick').'_', + )); + + self::nick_change(); + break; + default: + self::setConfig(array( + 'nick' => $new + )); + + self::nick_change(); + break; + } + } + + /** + * Envoie une notice a un salon / utilisateur + * + * @param string $to + * @param string $message + */ + public function notice ($to,$message) { + self::put('NOTICE '.$to.' :'.$message."\n"); + } + + /** + * Envoie un message (PRIVMSG) a un salon / utilisateur + * + * @param string $to + * @param string $message + * @todo wrap message to 512 char (max) + */ + public function privmsg ($to,$message) { + $search = array('#name'); + $replace = array(self::$myBotName); + $message = str_replace($search,$replace,$message); + self::put('PRIVMSG '.$to.' :'.$message."\n"); + } + + public function mprivmsg($to,$messages,$interval=650000) { + if (is_array($messages)) { + foreach ($messages as $msg) { + $this->privmsg($to,$msg); + usleep($interval); + } + } + } + + public function put($data) { + if (!is_resource($this->_socket)) { + throw new Exception('Connection lost...',1); + return; + } + + echo debug() ? 'bot::put() -> ' . $data . "\n" : ''; + + $ok = socket_write($this->_socket, $data ."\n"); + if ($ok) { + return true; + } else { + return false; + } + + return true; + } + + public function colors($msg,$text,$background=false) { + $color_tag = chr(3); + $first = ($background)?$color_tag.$text.','.$background:$color_tag.$text; + return $first.$msg.$color_tag; + } + + public function bold($msg) { + return chr(2).$msg.chr(2); + } + + public function ctcp($msg) { + return chr(1).$msg.chr(1); + } + + public function reverse_color($msg) { + return chr(22).$msg.chr(22); + } + + public function underline($msg) { + return chr(31).$msg.chr(31); + } + + public function paragraphe($msg) { + return explode("\n",$msg); + } + + public function getBotName() { + return self::getConfig('nick'); + } + +} + +?> \ No newline at end of file diff --git a/sources/IRCMain/Ctcp.php b/sources/IRCMain/Ctcp.php new file mode 100644 index 0000000..abc56b2 --- /dev/null +++ b/sources/IRCMain/Ctcp.php @@ -0,0 +1,82 @@ +_event = $event; + $this->_ircmain = $ircmain; + } + + function _stripMessage() { + $this->ctcpNotice = str_replace(chr(001), "", $this->_event->getDataMessage()); + } + + function _setRequest() { + + self::_stripMessage(); + + if (strstr($this->ctcpNotice,' ') === true) { + list($this->ctcpRequest,$this->ctcpQuery) = explode(" ",$this->ctcpNotice); + $this->ctcpRequest = trim($this->ctcpRequest); + } else { + $this->ctcpRequest = trim($this->ctcpNotice); + } + + } + + /** + * Return the ctcp responce + * + * @return string + */ + function getResponce() { + switch ($this->ctcpRequest) { + case self::CTCP_CLIENTINFO: + return 'PING VERSION TIME USERINFO CLIENTINFO'; + break; + + case self::CTCP_VERSION: + return 'IrBot version '.$this->_ircmain->getConfig('version').' - PHP '.phpversion().' -- on http://irbot.irstat.org'; + break; + + case self::CTCP_USERINFO: + return 'IrBot'; + break; + + case self::CTCP_TIME: + return date('Y-m-d H:i:s'); + break; + + case self::CTCP_PING: + return "PING " . $query; + break; + default: + return "UNKNOWN CTCP REQUEST : '$this->ctcpRequest'"; + break; + } + } +} +?> \ No newline at end of file -- 2.11.4.GIT