16
[irbot.git] / sources / main-class.inc.php
blob8d5f78947fb0e729c26a9c907c266746cfb7851c
1 <?php
2 /**
3 * This file is part of IrBot, irc robot.
4 * Copyright (C) 2007 Bellière Ludovic
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 final class bot {
22 // Timeout avant une reconnexion
23 public $socketTimeout = 280;
25 // Variables privées
26 static public $instance = FALSE;
28 protected $C;
30 static $botVersion = '1.0';
31 static $server;
32 static $port;
33 static $channel;
34 static $myBotName;
35 static $ip;
36 static $domain;
37 static $connection_password;
39 public $irc;
40 public $plugins;
41 public $formater;
42 public $base;
43 public $msg;
45 private $core_commands;
46 private $users_list;
47 private $msg_info;
49 public static function GetInstance() {
50 if (!self::$instance) {
51 self::$instance = new bot();
52 self::$instance->plugins = new plugins();
53 self::$instance->irc = new irc;
55 return self::$instance;
58 private function __construct() {
59 // load config and other things echo "oups main\n";die;
60 $this->formater = text_format::GetInstance();
63 private function load_core_plugin() {
64 // core plugin is an exeption in do_command
65 $this->plugins->add_command('core','shownick',0,'Show the current nick used (debug)','mixed');
66 $this->plugins->add_command('core','nick',1,'Change the current nick','mixed');
67 $this->plugins->add_command('core','quit',0,'Disconnect and stop the process','mixed');
68 $this->plugins->add_command('core','restart',0,'Disconnect and restart the process','mixed');
69 $this->plugins->add_command('core','help',0,'Hmm, je dois recoder cette fonction','mixed');
72 public function launch() {
73 self::load_core_plugin();
74 try {
75 $this->C = @fsockopen(self::$server, self::$port, $errno, $errstr, 10);
76 if (!$this->C) {
77 throw new Exception('Impossible de se connecter au server IRC !',0);
80 if (self::$connection_password !== false) {
81 $this->put('PASS '.self::$connection_password);
83 // TODO : be sure for the validity of the connection password (what chain server return if fail ?)
85 $this->put('USER '.self::$myBotName.' '.self::$myBotName.'@'.self::$ip.' '.self::$domain.' :XBOT');
86 $this->put('NICK '.self::$myBotName);
88 while (1) {
89 $this->msg = $this->get();
90 $this->irc->parse_get($this->msg);
92 $this->msg_info = $msg_info = $this->irc->get_msg_info();
94 switch ($msg_info['type']) {
96 case 'PRIVMSG':
98 // ctcp
99 if ($msg_info['message'][0] == chr(001)) {
101 // we don't need this character
102 $msg_info['message'] = str_replace(chr(001), "", $msg_info['message']);
103 if (strstr($msg_info['message'],' ')===true) {
104 list($cmd,$query) = explode(" ",$msg_info['message']);
105 } else {
106 $cmd = $msg_info['message'];
109 // we don't need this character
110 //$cmd = str_replace(chr(001), "", $msg_info['message']);
112 switch ($cmd) {
113 case 'CLIENTINFO':
114 self::notice($msg_info['from'],$this->formater->ctcp('PING VERSION TIME USERINFO CLIENTINFO'));
115 break;
117 case 'VERSION':
118 self::notice($msg_info['from'],$this->formater->ctcp('RPGBot version '.bot::$botVersion.' - PHP '.phpversion().' -- par Tornald et Bloodshed'));
119 break;
121 case 'USERINFO':
122 self::notice($msg_info['from'],$this->formater->ctcp('RPGBot'));
123 break;
125 case 'TIME':
126 self::notice($msg_info['from'],$this->formater->ctcp(date('Y-m-d H:i:s')));
127 break;
129 case 'PING':
130 self::notice($msg_info['from'],$this->formater->ctcp("PING ".$query));
131 break;
132 default:
133 self::notice($msg_info['from'],$this->formater->ctcp("UNKNOWN CTCP REQUEST : $cmd"));
134 break;
136 } else {
137 if ($msg_info['to'] == bot::$myBotName) {
138 // auth proccess
139 if (preg_match('`^connect ([^ ]+) ([^ ]+)`',$msg_info['message'],$m)) {
140 if ($m[1] == 'admin' && $m[2] == 'mypass') {
141 $this->auth = true;
142 self::notice($msg_info['from'],'Vous êtes bien authentifié comme administrateur.');
143 } else {
144 self::notice($msg_info['from'],'Erreur dans votre login et / ou mot de passe.');
146 continue;
150 if ($msg_info['message'][0] == '!') {
151 $message = substr($msg_info['message'],1);
152 $query = explode(' ',$message);
153 $query_count = count($query);
155 if (isset($this->plugins->commands[$query[0]])) {
156 if ($query_count > 1) {
158 if ($this->plugins->commands[$query[0]][$query[1]]['type'] == 'mixed' ||
159 ($msg_info['to'] == bot::$myBotName && $this->plugins->commands[$query[0]][$query[1]]['type'] == 'private') ||
160 ($msg_info['to'] == bot::$channel && $this->plugins->commands[$query[0]][$query[1]]['type'] == 'public')) {
162 * $query = array( plugins, method[, arg[, ...]] )
163 * !plugin method[ arg[ ...]]
165 call_user_func_array(array($this->plugins,'do_command'),array_merge(array('msg_info'=>$msg_info),$query));
166 } else {
167 print_r($msg_info);
168 echo $this->plugins->commands[$query[0]][$query[1]]['type']."\n";
169 $this->privmsg($msg_info['from'],"Error with the request.");
171 } else {
172 // no method : need a list of commands
173 $plugin = $message;
175 $commands = $this->plugins->list_command($plugin);
176 foreach ($commands as $command_info) {
177 if ($command_info['type'] == 'public') {
178 $get_plugin_method = '!'.$plugin;
179 } else {
180 $get_plugin_method = '/msg ' . bot::$myBotName . ' !' . $plugin;
183 $this->privmsg($msg_info['from'],$this->formater->bold('Command :')." $get_plugin_method {$command_info['method']}".(($command_info['accepted_args']>0)?' [some args...]':''));
185 $help = explode("\n",$command_info['help']);
186 foreach($help as $help_msg) {
187 $this->privmsg($msg_info['from'],$help_msg);
191 } else {
192 var_dump($this->plugins->commands);
194 } else {
195 echo 'debug: '.$msg_info['message'][0]."\n";
198 break;
199 case 'NOTICE':
200 break;
204 } catch (myRuntimeException $e) {
205 $x = $e->getMessage();
206 echo $x;
207 $x.= backtrace($e->getTrace());
208 file_put_contents('errorlog',$x);
209 //if ($e->_level < 2 || ($e->_level >= 256 && $e->_level < 1024)) {
210 echo 'Error level : '.$e->_level."\n\n";
211 throw new Exception('Error occured',0);
212 /*} else {
213 echo 'Error level : '.$e->_level."\n\n\n\n";
214 throw new Exception("Error occured. Please see errorlog for details.",1);
216 } catch (Exception $e) {
217 throw $e;
221 public function joinChannel($channel) {
222 $this->put('JOIN '.$channel);
223 echo "Join channel $channel ...\n";
226 private function nick_change() {
227 echo "New nick : ".self::$myBotName."\n";
228 $this->put('NICK :'.self::$myBotName);
231 public function newNick($new=false) {
232 switch ($new) {
233 case self::$myBotName:
234 echo "New nick : [ERR] no changes :". self::$myBotName . ' == ' . $new ."\n";
235 break;
236 case false:
237 self::$myBotName .= '_';
238 self::nick_change();
239 break;
240 default:
241 self::$myBotName = $new;
242 self::nick_change();
243 break;
248 * Envoie une notice a un salon / utilisateur
250 * @param string $to
251 * @param string $message
253 public function notice ($to,$message) {
254 self::put('NOTICE '.$to.' :'.$message."\n");
258 * Envoie un message (PRIVMSG) a un salon / utilisateur
260 * @param string $to
261 * @param string $message
263 public function privmsg ($to,$message) {
264 self::put('PRIVMSG '.$to.' :'.$message."\n");
267 public function put($command) {
268 if (!is_resource($this->C)) {
269 throw new Exception('Connection lost...',1);
271 echo debug() ? '[->' . $command . "\n" : '';
272 fputs($this->C, $command . "\n");
273 return true;
276 public function get() {
277 // Stream Timeout
278 stream_set_timeout($this->C, $this->socketTimeout);
280 $tmp1 = time();
281 $content = fgets($this->C, 1024);
283 echo debug() ? "<-]$content" : '';
285 if ($content != '') {
286 return $content;
289 // TIMEOUT
290 if (time()-$tmp1 >= $this->socketTimeout) {
291 throw new Exception('TIMEOUT',0);
295 public function shownick() {
296 $this->privmsg(bot::$channel,bot::$myBotName."\n");
299 public function nick($newNick) {
300 $this->newNick($newNick);
303 public function help() {
304 $this->privmsg($this->msg_info['from'],"List of plugins :");
305 foreach($this->plugins->plugin_list as $pluginName => $object) {
306 $this->privmsg($this->msg_info['from'],"!$pluginName");
307 usleep(500000);
311 public function restart() {
312 if ($this->auth) {
313 echo 'Restart...'."\n";
314 $this->disconnect();
315 sleep(5);
316 throw new Exception('Restart...',1);
317 } else {
318 $this->privmsg($this->msg_info['from'],"Vous n'êtes pas authentifié.");
322 public function quit() {
323 if ($this->auth) {
324 $this->disconnect();
325 throw new Exception('Quit from',3);
326 } else {
327 $this->privmsg($this->msg_info['from'],"Vous n'êtes pas authentifié.");
331 public function disconnect($msg='EOL ;') {
332 $this->plugins->unload_plugin('_all');
333 echo "Closing Link...";
334 if (is_resource($this->C)) {
335 $this->put('QUIT :'.$msg);
336 @fclose($this->C);
337 echo "\t\t\tdone.\n";
338 } else {
339 echo "\t\t\tError.\nConnection already breack down. ".'bot::disconnect'."\n";
341 return true;
344 private function load_user($file='users.db') {
345 echo "Loading users ...";
346 $ulist = explode("\n",file_get_contents($file));
347 foreach ($ulist as $user) {
348 list($uname,$upass,$uright) = explode(':',$user);
349 $this->users_list[$uname] = array($upass,$uright);
351 echo "\t\t\tdone.\n";
354 function __destruct() {
355 if (is_resource($this->C)) {
356 $this->put('QUIT :Error occured');
357 @fclose($this->C);