Show
Ignore:
Timestamp:
02/14/2008 08:30:06 PM (11 months ago)
Author:
Shadowhand
Message:

I <3 Kobot

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/modules/kobot/libraries/Kobot.php

    r2049 r2051  
    2121        protected $responses = array(); 
    2222 
     23        // Responses to drop by default 
     24        protected $dropped = array 
     25        ( 
     26                'NOTICE', 
     27                '001', 
     28                '002', 
     29                '003', 
     30                '004', 
     31                '005', 
     32                '251', 
     33                '252', 
     34                '254', 
     35                '255', 
     36                '265', 
     37                '266', 
     38                '250', 
     39                '366', 
     40                '477', 
     41        ); 
     42 
    2343        // IRC socket, MOTD, and stats 
    2444        protected $socket; 
     
    3050                'last_sent'          => 0, 
    3151                'last_received'      => 0, 
    32                 'commands_sent'      => 0, 
    33                 'commands_received'  => 0, 
    3452        ); 
    3553 
     
    3957        public function __construct($server, $port = NULL, $timeout = NULL) 
    4058        { 
    41                 echo Kohana::debug($this->parse(':anthony.freenode.net 353 koboto @ #koboto :koboto @Shadowhand'));exit; 
    42                  
    4359                if (PHP_SAPI !== 'cli') 
    4460                        throw new Kohana_Exception('kobot.command_line_only'); 
     
    7793                        $this->log(1, 'Connected to '.$server.':'.$port); 
    7894 
    79                         // Automatically reply to PING comamnds 
    80                         $this->set_response('ping', array($this, 'pong')); 
     95                        foreach ($this->dropped as $cmd) 
     96                        { 
     97                                // Drop all requested commands 
     98                                $this->set_response($cmd, array($this, 'response_drop')); 
     99                        } 
     100 
     101                        // Read the PING command 
     102                        $this->set_response('PING', array($this, 'response_ping')); 
     103 
     104                        // Read the MOTD command 
     105                        $this->set_response('375', array($this, 'response_motd')); 
     106                        $this->set_response('372', array($this, 'response_motd')); 
     107                        $this->set_response('376', array($this, 'response_motd')); 
     108 
     109                        // Read the USERS command 
     110                        $this->set_response('353', array($this, 'response_userlist')); 
     111 
     112                        // Read the JOIN command 
     113                        $this->set_response('JOIN', array($this, 'response_join')); 
     114 
     115                        // Read the PART command 
     116                        $this->set_response('PART', array($this, 'response_part')); 
    81117                } 
    82118                else 
     
    88124        } 
    89125 
    90         public function exception_handler($exception, $message = NULL, $file = NULL, $line = NULL) 
    91         { 
    92                 if (func_num_args() === 5) 
    93                 { 
    94                         if ((error_reporting() & $exception) !== 0) 
    95                         { 
    96                                 // PHP Error 
    97                                 $this->log(1, $message.' in '.$file.' on line '.$line); 
    98                         } 
    99                 } 
    100                 else 
    101                 { 
    102                         // Exception 
    103                         $this->log(1, $exception->getMessage()); 
    104                 } 
    105         } 
    106  
    107         public function log($level, $message) 
    108         { 
    109                 if ($level >= $this->log_level) 
    110                 { 
    111                         // Display the message with a timestamp, flush the output 
    112                         echo date('Y-m-d g:i:s').' --- '.$message."\n"; flush(); 
    113                 } 
    114         } 
    115  
    116         public function set_response($command, $callback) 
    117         { 
    118                 if ( ! is_callable($callback)) 
    119                         throw new Kohana_Exception('kobot.invalid_callback'); 
    120  
    121                 // Set the response callback 
    122                 $this->responses[$command] = $callback; 
    123  
    124                 return $this; 
    125         } 
    126  
    127126        public function login($username, $password = NULL, $realname = 'Kohana PHP Bot') 
    128127        { 
     
    133132                // Update the last ping 
    134133                $this->stats['last_ping'] = microtime(TRUE); 
    135  
    136                 // Set the MOTD response 
    137                 $this->set_response('375', array($this, 'read_motd')); 
    138                 $this->set_response('372', array($this, 'read_motd')); 
    139                 $this->set_response('376', array($this, 'read_motd')); 
    140         } 
    141  
    142         public function read_motd($data) 
    143         { 
    144                 switch ($data['command']) 
    145                 { 
    146                         case '375': 
    147                                 // Prepare to read the MOTD 
    148                                 $this->motd = array(); 
    149                         break; 
    150                         case '372': 
    151                                 // Read the MOTD 
    152                                 $this->motd[] = substr($data['message'], 2); 
    153                         break; 
    154                         case '376': 
    155                                 // Log the number of lines in the MOTD 
    156                                 $this->log(1, 'Read '.count($this->motd).' MOTD lines'); 
    157  
    158                                 // Make the MOTD into a string 
    159                                 $this->motd = implode("\n", $this->motd); 
    160                         break; 
    161                 } 
    162134        } 
    163135 
     
    171143                        // Join the channel 
    172144                        $this->send('JOIN '.$channel); 
    173  
    174                         // Read the USERS command 
    175                         $this->set_response('353', array($this, 'read_userlist')); 
    176145                } 
    177146        } 
     
    225194                while ( ! feof($this->socket)) 
    226195                { 
     196                        // Read the raw server stream, up to 512 characters 
    227197                        while ($raw = fgets($this->socket, 512)) 
    228198                        { 
    229                                 $this->log(2, '<<< '.trim($raw)); 
    230  
    231                                 // Parse the command 
    232                                 $data = array_combine(array('sender', 'sendhost', 'command', 'target', 'message'), $this->parse($raw)); 
    233  
    234                                 // Run the event 
    235                                 Event::run('kirc.'.strtolower($data['command']), $data); 
     199                                // Update the last received time 
     200                                $this->stats['last_received'] = microtime(TRUE); 
     201 
     202                                // Parse the raw string into a command array 
     203                                $data = $this->parse($raw); 
     204 
     205                                if (isset($this->responses[$data['command']])) 
     206                                { 
     207                                        // Call the response handler 
     208                                        call_user_func($this->responses[$data['command']], $data); 
     209                                } 
     210                                else 
     211                                { 
     212                                        // Debug the response 
     213                                        $this->log(2, 'NOT FOUND: '.$data['command'].' <<< '.trim($raw)); 
     214                                } 
    236215                        } 
    237216                        // One half-second is high enough interactivity 
     
    240219        } 
    241220 
    242         // Return: array(sender, sendhost, command, target, message) 
     221        /** 
     222         * Parses are raw server string into a command array. 
     223         * 
     224         * @param   string   raw server string 
     225         * @return  array    sender, sendhost, command, target, message 
     226         */ 
    243227        protected function parse($raw) 
    244228        { 
     
    275259                        } 
    276260 
    277                         // CMD str, Extract the command from the remaining string 
    278                         list ($data['command'], $str) = explode(' ', $str, 2); 
    279  
    280                         if (strpos($str, ' :') !== FALSE) 
    281                         { 
    282                                 // target :message, some kind of communication 
    283                                 list ($data['target'], $data['message']) = explode(' :', $params, 2); 
    284                         } 
    285                         elseif ($str{0} === ':') 
    286                         { 
    287                                 // :target, without a message 
    288                                 $data['target'] = substr($str, 1); 
     261                        if (strpos($str, ' ') !== FALSE) 
     262                        { 
     263                                // CMD str, Extract the command from the remaining string 
     264                                list ($data['command'], $str) = explode(' ', $str, 2); 
     265 
     266                                if (strpos($str, ' :') !== FALSE) 
     267                                { 
     268                                        // target :message, some kind of communication 
     269                                        list ($data['target'], $data['message']) = explode(' :', $str, 2); 
     270                                } 
     271                                elseif ($str{0} === ':') 
     272                                { 
     273                                        // :target, without a message 
     274                                        $data['target'] = substr($str, 1); 
     275                                } 
     276                                else 
     277                                { 
     278                                        // target, with nothing 
     279                                        $data['target'] = $str; 
     280                                } 
    289281                        } 
    290282                        else 
    291283                        { 
    292                                 $data['target'] = $str; 
     284                                $data['command'] = $str; 
    293285                        } 
    294286                } 
     
    341333                                                        if ($command === 'say hello') 
    342334                                                        { 
    343                                                                 $this->send('PRIVMSG '.$data['channel'].' :Go away, '.$data['nickname'].'!'); 
     335                                                                ; 
    344336                                                        } 
    345337                                                        elseif (preg_match('/^r(\d+)$/', $command, $match)) 
     
    402394        } 
    403395 
     396        public function log($level, $message) 
     397        { 
     398                if ($level >= $this->log_level) 
     399                { 
     400                        // Display the message with a timestamp, flush the output 
     401                        echo date('Y-m-d g:i:s').' --- '.$message."\n"; flush(); 
     402                } 
     403        } 
     404 
     405        public function exception_handler($e, $message = NULL, $file = NULL, $line = NULL) 
     406        { 
     407                if (func_num_args() === 5) 
     408                { 
     409                        if ((error_reporting() & $e) !== 0) 
     410                        { 
     411                                // PHP Error 
     412                                $this->log(1, $message.' in '.$file.' on line '.$line); 
     413                        } 
     414                } 
     415                else 
     416                { 
     417                        // Exception 
     418                        $this->log(1, strip_tags($e->getMessage()).' File: '.$e->getFile().' on line '.$e->getLine()); 
     419                } 
     420        } 
     421 
     422        public function add_trigger($callback, $pattern) 
     423        { 
     424                // TODO 
     425                return $this; 
     426        } 
     427 
     428        public function set_response($command, $callback) 
     429        { 
     430                if ( ! is_callable($callback)) 
     431                        throw new Kohana_Exception('kobot.invalid_callback', $command); 
     432 
     433                // Set the response callback 
     434                $this->responses[$command] = $callback; 
     435 
     436                return $this; 
     437        } 
     438 
    404439        /** 
    405440         * Kobot default responses. You can overload these in your own extension class, 
     
    407442         */ 
    408443 
    409         public function response_drop($data) 
    410         { 
    411                 // Log dropped responses 
    412                 $this->log(2, $data); 
    413         } 
    414  
     444        // * 
     445        public function response_drop() 
     446        { 
     447                // Silence is golden 
     448        } 
     449 
     450        // PING 
    415451        public function response_ping($data) 
    416452        { 
     453                // Update the stats 
     454                $this->stats['last_ping'] = microtime(TRUE); 
     455 
    417456                // Reply with a PONG 
    418457                $this->send('PONG '.substr($data['message'], 1)); 
    419458        } 
    420459 
    421         // 353 
     460        // 375, 372+, 376 
     461        public function response_motd($data) 
     462        { 
     463                switch ($data['command']) 
     464                { 
     465                        case '375': 
     466                                // Prepare to read the MOTD 
     467                                $this->motd = array(); 
     468                        break; 
     469                        case '372': 
     470                                // Read the MOTD 
     471                                $this->motd[] = substr($data['message'], 2); 
     472                        break; 
     473                        case '376': 
     474                                // Log the number of lines in the MOTD 
     475                                $this->log(1, 'Read '.count($this->motd).' MOTD lines'); 
     476 
     477                                // Make the MOTD into a string 
     478                                $this->motd = implode("\n", $this->motd); 
     479                        break; 
     480                } 
     481        } 
     482 
     483        // 353, 366 
    422484        public function response_userlist($data) 
    423485        { 
     
    431493 
    432494                        // Log the user count 
    433                         $this->log(1, 'Read '.count($this->channels[$channel]).' users'); 
     495                        $this->log(1, 'Found '.count($this->channels[$channel]).' users in channel'); 
     496                } 
     497        } 
     498 
     499        // JOIN 
     500        public function response_join($data) 
     501        { 
     502                // Make sure the bot is joined to the target channel 
     503                if (isset($this->channels[$data['target']])) 
     504                { 
     505                        // Only add the user if they are not already in the list 
     506                        if ( ! in_array($data['sender'], $this->channels[$data['target']])) 
     507                        { 
     508                                // Add the sender to the channel userlist 
     509                                $this->channels[$data['target']][] = $data['sender']; 
     510 
     511                                // Debug the join 
     512                                $this->log(2, '> '.$data['sender'].' ('.$data['target'].')'); 
     513                        } 
     514                } 
     515        } 
     516 
     517        // PART 
     518        public function response_part($data) 
     519        { 
     520                // Make sure the bot is joined to the target channel 
     521                if (isset($this->channels[$data['target']])) 
     522                { 
     523                        // Only remove the user if they are in the list 
     524                        if (($key = array_search($data['sender'], $this->channels[$data['target']])) !== FALSE) 
     525                        { 
     526                                // Remove the sender from the channel userlist 
     527                                unset($this->channels[$data['target']][$key]); 
     528 
     529                                // Debug the join 
     530                                $this->log(2, '< '.$data['sender'].' ('.$data['target'].')'); 
     531                        } 
    434532                } 
    435533        }