19
[irbot.git] / sources / main-class.inc.php
blob62ce2e9e6a2b86713ff2324f5b450ebb7caa88aa
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();
61 $this->tick = new tick();
64 private function load_core_plugin() {
65 // core plugin is an exeption in do_command
66 $this->plugins->add_command('core','shownick',0,'Show the current nick used (debug)','mixed');
67 $this->plugins->add_command('core','nick',1,'Change the current nick','mixed');
68 $this->plugins->add_command('core','quit',0,'Disconnect and stop the process','mixed');
69 $this->plugins->add_command('core','restart',0,'Disconnect and restart the process','mixed');
70 $this->plugins->add_command('core','help',0,'Hmm, je dois recoder cette fonction','mixed');
73 public function launch() {
74 self::load_core_plugin();
75 try {
76 $this->C = @fsockopen(self::$server, self::$port, $errno, $errstr, 10);
77 if (!$this->C) {
78 throw new Exception('Impossible de se connecter au server IRC !',0);
81 if (self::$connection_password !== false) {
82 $this->put('PASS '.self::$connection_password);
84 // TODO : be sure for the validity of the connection password (what chain server return if fail ?)
86 $this->put('USER '.self::$myBotName.' '.self::$myBotName.'@'.self::$ip.' '.self::$domain.' :XBOT');
87 $this->put('NICK '.self::$myBotName);
89 while (1) {
90 $this->msg = $this->get();
91 $this->irc->parse_get($this->msg);
93 $this->msg_info = $msg_info = $this->irc->get_msg_info();
95 switch ($msg_info['type']) {
97 case 'PRIVMSG':
99 // ctcp
100 if ($msg_info['message'][0] == chr(001)) {
102 // we don't need this character
103 $msg_info['message'] = str_replace(chr(001), "", $msg_info['message']);
104 if (strstr($msg_info['message'],' ')===true) {
105 list($cmd,$query) = explode(" ",$msg_info['message']);
106 } else {
107 $cmd = $msg_info['message'];
110 // we don't need this character
111 //$cmd = str_replace(chr(001), "", $msg_info['message']);
113 switch ($cmd) {
114 case 'CLIENTINFO':
115 self::notice($msg_info['from'],$this->formater->ctcp('PING VERSION TIME USERINFO CLIENTINFO'));
116 break;
118 case 'VERSION':
119 self::notice($msg_info['from'],$this->formater->ctcp('RPGBot version '.bot::$botVersion.' - PHP '.phpversion().' -- par Tornald et Bloodshed'));
120 break;
122 case 'USERINFO':
123 self::notice($msg_info['from'],$this->formater->ctcp('RPGBot'));
124 break;
126 case 'TIME':
127 self::notice($msg_info['from'],$this->formater->ctcp(date('Y-m-d H:i:s')));
128 break;
130 case 'PING':
131 self::notice($msg_info['from'],$this->formater->ctcp("PING ".$query));
132 break;
133 default:
134 self::notice($msg_info['from'],$this->formater->ctcp("UNKNOWN CTCP REQUEST : $cmd"));
135 break;
137 } else {
138 if ($msg_info['to'] == bot::$myBotName) {
139 // auth proccess
140 if (preg_match('`^connect ([^ ]+) ([^ ]+)`',$msg_info['message'],$m)) {
141 if ($m[1] == 'admin' && $m[2] == 'mypass') {
142 $this->auth = true;
143 self::notice($msg_info['from'],'Vous êtes bien authentifié comme administrateur.');
144 } else {
145 self::notice($msg_info['from'],'Erreur dans votre login et / ou mot de passe.');
147 continue;
151 if ($msg_info['message'][0] == '!') {
152 $message = substr($msg_info['message'],1);
153 $query = explode(' ',$message);
154 $query_count = count($query);
156 if (isset($this->plugins->commands[$query[0]])) {
157 if ($query_count > 1) {
159 if ($this->plugins->commands[$query[0]][$query[1]]['type'] == 'mixed' ||
160 ($msg_info['to'] == bot::$myBotName && $this->plugins->commands[$query[0]][$query[1]]['type'] == 'private') ||
161 ($msg_info['to'] == bot::$channel && $this->plugins->commands[$query[0]][$query[1]]['type'] == 'public')) {
163 * $query = array( plugins, method[, arg[, ...]] )
164 * !plugin method[ arg[ ...]]
166 call_user_func_array(array($this->plugins,'do_command'),array_merge(array('msg_info'=>$msg_info),$query));
167 } else {
168 print_r($msg_info);
169 echo $this->plugins->commands[$query[0]][$query[1]]['type']."\n";
170 $this->privmsg($msg_info['from'],"Error with the request.");
172 } else {
173 // no method : need a list of commands
174 $plugin = $message;
176 $commands = $this->plugins->list_command($plugin);
177 foreach ($commands as $command_info) {
178 if ($command_info['type'] == 'public') {
179 $get_plugin_method = '!'.$plugin;
180 } else {
181 $get_plugin_method = '/msg ' . bot::$myBotName . ' !' . $plugin;
184 $this->privmsg($msg_info['from'],$this->formater->bold('Command :')." $get_plugin_method {$command_info['method']}".(($command_info['accepted_args']>0)?' [some args...]':''));
186 $help = explode("\n",$command_info['help']);
187 foreach($help as $help_msg) {
188 $this->privmsg($msg_info['from'],$help_msg);
192 } else {
193 var_dump($this->plugins->commands);
195 } else {
196 echo 'debug: '.$msg_info['message'][0]."\n";
199 break;
200 case 'NOTICE':
201 break;
204 $this->tick->doAllTicks();
207 } catch (myRuntimeException $e) {
208 $x = $e->getMessage();
209 echo $x;
210 $x.= backtrace($e->getTrace());
211 file_put_contents('errorlog',$x);
212 //if ($e->_level < 2 || ($e->_level >= 256 && $e->_level < 1024)) {
213 echo 'Error level : '.$e->_level."\n\n";
214 throw new Exception('Error occured',0);
215 /*} else {
216 echo 'Error level : '.$e->_level."\n\n\n\n";
217 throw new Exception("Error occured. Please see errorlog for details.",1);
219 } catch (Exception $e) {
220 throw $e;
224 public function joinChannel($channel) {
225 $this->put('JOIN '.$channel);
226 echo "Join channel $channel ...\n";
229 private function nick_change() {
230 echo "New nick : ".self::$myBotName."\n";
231 $this->put('NICK :'.self::$myBotName);
234 public function newNick($new=false) {
235 switch ($new) {
236 case self::$myBotName:
237 echo "New nick : [ERR] no changes :". self::$myBotName . ' == ' . $new ."\n";
238 break;
239 case false:
240 self::$myBotName .= '_';
241 self::nick_change();
242 break;
243 default:
244 self::$myBotName = $new;
245 self::nick_change();
246 break;
251 * Envoie une notice a un salon / utilisateur
253 * @param string $to
254 * @param string $message
256 public function notice ($to,$message) {
257 self::put('NOTICE '.$to.' :'.$message."\n");
261 * Envoie un message (PRIVMSG) a un salon / utilisateur
263 * @param string $to
264 * @param string $message
266 public function privmsg ($to,$message) {
267 self::put('PRIVMSG '.$to.' :'.$message."\n");
270 public function put($command) {
271 if (!is_resource($this->C)) {
272 throw new Exception('Connection lost...',1);
274 echo debug() ? '[->' . $command . "\n" : '';
275 fputs($this->C, $command . "\n");
276 return true;
279 public function get() {
280 // Stream Timeout
281 stream_set_timeout($this->C, $this->socketTimeout);
283 $tmp1 = time();
284 $content = fgets($this->C, 1024);
286 echo debug() ? "<-]$content" : '';
288 if ($content != '') {
289 return $content;
292 // TIMEOUT
293 if (time()-$tmp1 >= $this->socketTimeout) {
294 throw new Exception('TIMEOUT',0);
298 public function shownick() {
299 $this->privmsg(bot::$channel,bot::$myBotName."\n");
302 public function nick($newNick) {
303 $this->newNick($newNick);
306 public function help() {
307 $this->privmsg($this->msg_info['from'],"List of plugins :");
308 foreach($this->plugins->plugin_list as $pluginName => $object) {
309 $this->privmsg($this->msg_info['from'],"!$pluginName");
310 usleep(500000);
314 public function restart() {
315 if ($this->auth) {
316 echo 'Restart...'."\n";
317 $this->disconnect();
318 sleep(5);
319 throw new Exception('Restart...',1);
320 } else {
321 $this->privmsg($this->msg_info['from'],"Vous n'êtes pas authentifié.");
325 public function quit() {
326 if ($this->auth) {
327 $this->disconnect();
328 throw new Exception('Quit from',3);
329 } else {
330 $this->privmsg($this->msg_info['from'],"Vous n'êtes pas authentifié.");
334 public function disconnect($msg='EOL ;') {
335 $this->plugins->unload_plugin('_all');
336 echo "Closing Link...";
337 if (is_resource($this->C)) {
338 $this->put('QUIT :'.$msg);
339 @fclose($this->C);
340 echo "\t\t\tdone.\n";
341 } else {
342 echo "\t\t\tError.\nConnection already breack down. ".'bot::disconnect'."\n";
344 return true;
347 private function load_user($file='users.db') {
348 echo "Loading users ...";
349 $ulist = explode("\n",file_get_contents($file));
350 foreach ($ulist as $user) {
351 list($uname,$upass,$uright) = explode(':',$user);
352 $this->users_list[$uname] = array($upass,$uright);
354 echo "\t\t\tdone.\n";
357 function __destruct() {
358 if (is_resource($this->C)) {
359 $this->put('QUIT :Error occured');
360 @fclose($this->C);