bot poc
authorMichael Wallner <mike@php.net>
Mon, 24 Jun 2013 05:15:22 +0000 (07:15 +0200)
committerMichael Wallner <mike@php.net>
Mon, 24 Jun 2013 05:15:22 +0000 (07:15 +0200)
bot/bot.php [new file with mode: 0644]

diff --git a/bot/bot.php b/bot/bot.php
new file mode 100644 (file)
index 0000000..1eff465
--- /dev/null
@@ -0,0 +1,208 @@
+<?php
+
+namespace irc\client;
+
+/* PHP-5.3 */
+function origin($origin, $key) {
+       $origin = parse_origin($origin);
+       return $origin[$key];
+}
+
+class Robot extends Session
+{
+       protected $config;
+       protected $connected = false;
+       protected $joined = array();
+       protected $work = array();
+       
+       function __construct($config) {
+               $this->configure($config);
+               parent::__construct($this->config->nick, $this->config->user, $this->config->real);
+       }
+       
+       function run() {
+               printf("Connecting to %s...\n", $this->config->host);
+               $this->doConnect($this->config->ipv6, $this->config->host, $this->config->port ?: 6667);
+               
+               for (   stream_set_blocking(STDIN, 0), $i = 0, $x = ["–","\\","|","/"];
+                               false !== ($fds = @parent::run(array(STDIN), null, 1));
+                               ++$i) {
+                       if (!$this->isConnected()) {
+                               printf("  %s \r", $x[$i%4]);
+                       }
+                       if ($fds[0]) {
+                               switch ($command = fgets(STDIN)) {
+                               case "quit\n":
+                                       $this->disconnect();
+                                       break 2;
+                               case "reload\n":
+                                       $this->reload();
+                                       break;
+                               case "update\n":
+                                       $this->update();
+                                       break;
+                               default:
+                                       $this->doRaw($command);
+                               }
+                       } else {
+                               $this->work();
+                       }
+               }
+               
+               printf("Bye!\n");
+       }
+       
+       function isConnected() {
+               return $this->connected;
+       }
+       
+       function disconnect() {
+               $this->connected = false;
+               parent::disconnect();
+       }
+       
+       function configure($config) {
+               $this->config = (object) (parse_ini_file($config, true) + ["config" => $config]);
+       }
+       
+       function reload() {
+               printf("Reloading config...\n");
+               $this->configure($this->config->config);
+               $this->join();
+       }
+       
+       function update() {
+               foreach ($this->joined as $channel) {
+                       $this->doNames($channel);
+               }
+       }
+       
+       function eventName($event) {
+               static $map;
+               
+               if (empty($map)) {
+                       $rfl = new \ReflectionExtension("ircclient");
+                       $map = array_map(function($v) {
+                               return substr($v, 11);
+                       }, array_flip(
+                               $rfl->getConstants()
+                       ));
+               }
+               
+               return isset($map[$event]) ? $map[$event] : "UNKNOWN_$event";
+       }
+       
+       function work() {
+               if (!empty($this->work)) {
+                       printf("Checking work queue (%d)\n", $this->eventName($event), count($this->work));
+                       list($cb_func, $cb_args) = array_shift($this->work);
+                       call_user_func_array($cb_func, $cb_args);
+               }
+       }
+       
+       function onError($origin, array $args) {
+               fprintf(STDERR, "ERROR: %s %s\n", $origin, implode(" ", $args));
+       }
+       
+       function onNumeric($origin, $event, array $args) {
+               static $buf = array();
+
+               switch($event) {
+               case RPL_NAMREPLY:
+                       if ((list(,, $channel, $users) = $args)) {
+                               $buf["names"][$channel] = array_merge((array) $buf["names"][$channel], explode(" ", $users));
+                       }
+                       break;
+                       
+               case RPL_ENDOFNAMES:
+                       if ((list(, $channel) = $args)) {
+                               foreach ($buf["names"][$channel] as $user) {
+                                       if ($user{0} === "@") {
+                                               $user = substr($user, 1);
+                                       }
+                                       if ($user !== $this->config->nick) {
+                                               printf("Adding work: WHOIS %s\n", $user);
+                                               $this->work[] = [
+                                                       [$this, "doWhois"],
+                                                       [$user]
+                                               ];
+                                       }
+                               }
+                       }
+                       $buf["names"][$channel] = array();
+                       break;
+                       
+               case RPL_WHOISUSER:
+                       if ((list(, $nick, $user, $host, , $real) = $args)) {
+                               $this->op(substr($user, 1) ."@" . $host);
+                       }
+                       break;
+               }
+               
+               fprintf(STDERR, "DEBUG: %s %s %s\n", $origin, $this->eventName($event), "<".implode("> <", $args).">");
+       }
+       
+       function onConnect($origin, array $args) {
+               list($nick) = $args;
+               $this->connected = true;
+               printf("Connected to %s as %s\n", $origin, $nick);
+               $this->join();
+       }
+       
+       function join() {
+               $nopart = array();
+               foreach (array_filter((array) $this->config, "is_array") as $channel => $config) {
+                       $nopart[] = $channel;
+                       printf("Joining %s...\n", $channel);
+                       $this->doJoin($channel, strlen($config["pass"]) ? $config["pass"] : NULL);
+               }
+               foreach (array_diff($this->joined, $nopart) as $channel) {
+                       printf("Leaving %s...\n", $channel);
+                       $this->doPart($channel);
+               }
+       }
+       
+       function op($channel, $origin) {
+               if (preg_match($this->config->{$channel}["oper"], $origin)) {
+                       $nick = origin($origin, "nick");
+                       printf("Set +o %s\n", $nick);
+                       $this->doChannelMode($channel, "+o $nick");
+               }
+       }
+       
+       function onPart($origin, array $args) {
+               $nick = origin($origin, "nick");
+               
+               if ($nick == $this->config->nick && (list($channel) = $args)) {
+                       printf("Left %s\n", $channel);
+                       unset($this->joined[array_search($this->joined, $channel, true)]);
+               }
+       }
+
+       function onJoin($origin, array $args) {
+               list($channel) = $args;
+               $nick = origin($origin, "nick");
+
+               if ($nick === $this->config->nick) {
+                       printf("Joined %s\n", $channel);
+                       $this->joined[] = $channel;
+               } else {
+                       printf("%s joined %s\n", $origin, $channel);
+                       $this->op($channel, $origin);
+               }
+       }
+       
+       function onMode($origin, array $args) {
+               if (count($args) >= 3) {
+                       list($channel, $mode, $users) = $args;
+
+                       if ($mode === "+o") {
+                               printf("Got +o %s\n", $users);
+                               
+                               if (preg_match(sprintf("/\b%s\b/", preg_quote($this->config->nick)), $users)) {
+                                       $this->doNames($channel);
+                               }
+                       }
+               }
+       }
+}