14
[irbot.git] / sources / main-class.inc.php
blobafb2fddd3b95bc74efa503a5106e9beb44c1d96d
1 <?php
3 final class bot {
5 // Timeout avant une reconnexion
6 public $socketTimeout = 280;
8 // Variables privées
9 static public $instance = FALSE;
11 protected $C;
13 static $botVersion = '1.0';
14 static $server;
15 static $port;
16 static $channel;
17 static $myBotName;
18 static $ip;
19 static $domain;
20 static $connection_password;
22 public $irc;
23 public $plugins;
24 public $formater;
25 public $base;
26 public $msg;
28 private $core_commands;
29 private $users_list;
31 public static function GetInstance() {
32 if (!self::$instance) {
33 self::$instance = new bot();
34 self::$instance->plugins = new plugins;
35 self::$instance->irc = new irc;
37 return self::$instance;
40 private function __construct() {
41 // load config and other things echo "oups main\n";die;
42 $this->formater = text_format::GetInstance();
45 private function load_core_plugin() {
46 // core plugin is an exeption in do_command
47 $this->plugins->add_command('core','shownick',0,'Show the current nick used (debug)');
48 $this->plugins->add_command('core','nick',1,'Change the current nick');
49 $this->plugins->add_command('core','quit',0,'Disconnect and stop the process');
50 $this->plugins->add_command('core','restart',0,'Disconnect and restart the process');
51 $this->plugins->add_command('core','help',0,'Hmm, je dois recoder cette fonction');
54 public function launch() {
55 self::load_core_plugin();
56 try {
57 $this->C = @fsockopen(self::$server, self::$port, $errno, $errstr, 10);
58 if (!$this->C) {
59 throw new Exception('Impossible de se connecter au server IRC !',0);
62 if (self::$connection_password !== false) {
63 $this->put('PASS '.self::$connection_password);
65 // TODO : be sure for the validity of the connection password (what chain server return if fail ?)
67 $this->put('USER '.self::$myBotName.' '.self::$myBotName.'@'.self::$ip.' '.self::$domain.' :XBOT');
68 $this->put('NICK '.self::$myBotName);
70 while (1) {
71 $this->msg = $this->get();
72 $this->irc->parse_get($this->msg);
74 $msg_info = $this->irc->get_msg_info();
76 switch ($msg_info['type']) {
78 case 'PRIVMSG':
80 // ctcp
81 if ($msg_info['message'][0] == chr(001)) {
83 // we don't need this character
84 $msg_info['message'] = str_replace(chr(001), "", $msg_info['message']);
85 if (strstr($msg_info['message'],' ')===true) {
86 list($cmd,$query) = explode(" ",$msg_info['message']);
87 } else {
88 $cmd = $msg_info['message'];
91 // we don't need this character
92 //$cmd = str_replace(chr(001), "", $msg_info['message']);
94 switch ($cmd) {
95 case 'CLIENTINFO':
96 self::notice($msg_info['from'],$this->formater->ctcp('PING VERSION TIME USERINFO CLIENTINFO'));
97 break;
99 case 'VERSION':
100 self::notice($msg_info['from'],$this->formater->ctcp('RPGBot version '.bot::$botVersion.' - PHP '.phpversion().' -- par Tornald et Bloodshed'));
101 break;
103 case 'USERINFO':
104 self::notice($msg_info['from'],$this->formater->ctcp('RPGBot'));
105 break;
107 case 'TIME':
108 self::notice($msg_info['from'],$this->formater->ctcp(date('Y-m-d H:i:s')));
109 break;
111 case 'PING':
112 self::notice($msg_info['from'],$this->formater->ctcp("PING ".$query));
113 break;
114 default:
115 self::notice($msg_info['from'],$this->formater->ctcp("UNKNOWN CTCP REQUEST : $cmd"));
116 break;
118 } else {
119 if ($msg_info['to'] == bot::$myBotName) {
120 // auth proccess
121 if (preg_match('`^connect ([^ ]+) ([^ ]+)`',$msg_info['message'],$m)) {
122 if ($m[1] == 'admin' && $m[2] == 'mypass') {
123 $this->auth = true;
124 self::notice($msg_info['from'],'Vous êtes bien authentifié comme administrateur.');
125 } else {
126 self::notice($msg_info['from'],'Erreur dans votre login et / ou mot de passe.');
128 continue;
132 if ($msg_info['message'][0] == '!') {
133 $message = substr($msg_info['message'],1);
134 $query = explode(' ',$message);
135 $query_count = count($query);
137 if (isset($this->plugins->commands[$query[0]])) {
138 if ($query_count > 1) {
139 if ($this->plugins->commands[$query[0]][$query[1]]['type'] == 'mixed' ||
140 $msg_info['to'] == bot::$myBotName && $this->plugins->commands[$query[0]][$query[1]]['type'] == 'private' ||
141 $msg_info['to'] == bot::$channel && $this->plugins->commands[$query[0]][$query[1]]['type'] == 'public') {
143 * $query = array( plugins, method[, arg[, ...]] )
144 * !plugin method[ arg[ ...]]
146 call_user_func_array(array($this->plugins,'do_command'),array_merge(array('msg_info'=>$msg_info),$query));
148 } else {
149 // no method : need a list of commands
150 $plugin = $message;
152 $commands = $this->plugins->list_command($plugin);
153 foreach ($commands as $command_info) {
154 if ($command_info['type'] == 'public') {
155 $get_plugin_method = '!'.$plugin;
156 } else {
157 $get_plugin_method = '/msg ' . bot::$myBotName . ' !' . $plugin;
160 $this->privmsg($msg_info['from'],$this->formater->bold('Command :')." $get_plugin_method {$command_info['method']}".(($command_info['accepted_args']>0)?' [some args...]':''));
162 $help = explode("\n",$command_info['help']);
163 foreach($help as $help_msg) {
164 $this->privmsg($msg_info['from'],$help_msg);
168 } else {
169 var_dump($this->plugins->commands);
171 } else {
172 echo 'debug: '.$msg_info['message'][0]."\n";
175 break;
176 case 'NOTICE':
177 break;
181 } catch (myRuntimeException $e) {
182 $x = $e->getMessage();
183 echo $x;
184 $x.= backtrace($e->getTrace());
185 file_put_contents('errorlog',$x);
186 //if ($e->_level < 2 || ($e->_level >= 256 && $e->_level < 1024)) {
187 echo 'Error level : '.$e->_level."\n\n";
188 throw new Exception('Error occured',0);
189 /*} else {
190 echo 'Error level : '.$e->_level."\n\n\n\n";
191 throw new Exception("Error occured. Please see errorlog for details.",1);
193 } catch (Exception $e) {
194 throw $e;
198 public function joinChannel($channel) {
199 $this->put('JOIN '.$channel);
200 echo "Join channel $channel ...\n";
203 private function nick_change() {
204 echo "New nick : ".self::$myBotName."\n";
205 $this->put('NICK :'.self::$myBotName);
208 public function newNick($new=false) {
209 switch ($new) {
210 case self::$myBotName:
211 echo "New nick : [ERR] no changes :". self::$myBotName . ' == ' . $new ."\n";
212 break;
213 case false:
214 self::$myBotName .= '_';
215 self::nick_change();
216 break;
217 default:
218 self::$myBotName = $new;
219 self::nick_change();
220 break;
225 * Envoie une notice a un salon / utilisateur
227 * @param string $to
228 * @param string $message
230 public function notice ($to,$message) {
231 self::put('NOTICE '.$to.' :'.$message."\n");
235 * Envoie un message (PRIVMSG) a un salon / utilisateur
237 * @param string $to
238 * @param string $message
240 public function privmsg ($to,$message) {
241 self::put('PRIVMSG '.$to.' :'.$message."\n");
244 public function put($command) {
245 if (!is_resource($this->C)) {
246 throw new Exception('Connection lost...',1);
248 echo debug() ? '[->' . $command . "\n" : '';
249 fputs($this->C, $command . "\n");
250 return true;
253 public function get() {
254 // Stream Timeout
255 stream_set_timeout($this->C, $this->socketTimeout);
257 $tmp1 = time();
258 $content = fgets($this->C, 1024);
260 echo debug() ? "<-]$content" : '';
262 if ($content != '') {
263 return $content;
266 // TIMEOUT
267 if (time()-$tmp1 >= $this->socketTimeout) {
268 throw new Exception('TIMEOUT',0);
272 public function disconnect($msg='EOL ;') {
273 echo 'Closing Link...'."\n";
274 $this->put('QUIT :'.$msg);
275 if (is_resource($this->C)) {
276 @fclose($this->C);
277 } else {
278 echo "There is no link to close (->C is not a resource) !\n";
280 return true;
283 private function load_user($file='users.db') {
284 echo "Loading users ...";
285 $ulist = explode("\n",file_get_contents($file));
286 foreach ($ulist as $user) {
287 list($uname,$upass,$uright) = explode(':',$user);
288 $this->users_list[$uname] = array($upass,$uright);
290 echo "\t\t\tdone.\n";
293 function __destruct() {
294 self::disconnect('Error occured');