bot poc
[m6w6/ext-ircclient] / bot / bot.php
1 <?php
2
3 namespace irc\client;
4
5 /* PHP-5.3 */
6 function origin($origin, $key) {
7 $origin = parse_origin($origin);
8 return $origin[$key];
9 }
10
11 class Robot extends Session
12 {
13 protected $config;
14 protected $connected = false;
15 protected $joined = array();
16 protected $work = array();
17
18 function __construct($config) {
19 $this->configure($config);
20 parent::__construct($this->config->nick, $this->config->user, $this->config->real);
21 }
22
23 function run() {
24 printf("Connecting to %s...\n", $this->config->host);
25 $this->doConnect($this->config->ipv6, $this->config->host, $this->config->port ?: 6667);
26
27 for ( stream_set_blocking(STDIN, 0), $i = 0, $x = ["–","\\","|","/"];
28 false !== ($fds = @parent::run(array(STDIN), null, 1));
29 ++$i) {
30 if (!$this->isConnected()) {
31 printf(" %s \r", $x[$i%4]);
32 }
33 if ($fds[0]) {
34 switch ($command = fgets(STDIN)) {
35 case "quit\n":
36 $this->disconnect();
37 break 2;
38 case "reload\n":
39 $this->reload();
40 break;
41 case "update\n":
42 $this->update();
43 break;
44 default:
45 $this->doRaw($command);
46 }
47 } else {
48 $this->work();
49 }
50 }
51
52 printf("Bye!\n");
53 }
54
55 function isConnected() {
56 return $this->connected;
57 }
58
59 function disconnect() {
60 $this->connected = false;
61 parent::disconnect();
62 }
63
64 function configure($config) {
65 $this->config = (object) (parse_ini_file($config, true) + ["config" => $config]);
66 }
67
68 function reload() {
69 printf("Reloading config...\n");
70 $this->configure($this->config->config);
71 $this->join();
72 }
73
74 function update() {
75 foreach ($this->joined as $channel) {
76 $this->doNames($channel);
77 }
78 }
79
80 function eventName($event) {
81 static $map;
82
83 if (empty($map)) {
84 $rfl = new \ReflectionExtension("ircclient");
85 $map = array_map(function($v) {
86 return substr($v, 11);
87 }, array_flip(
88 $rfl->getConstants()
89 ));
90 }
91
92 return isset($map[$event]) ? $map[$event] : "UNKNOWN_$event";
93 }
94
95 function work() {
96 if (!empty($this->work)) {
97 printf("Checking work queue (%d)\n", $this->eventName($event), count($this->work));
98 list($cb_func, $cb_args) = array_shift($this->work);
99 call_user_func_array($cb_func, $cb_args);
100 }
101 }
102
103 function onError($origin, array $args) {
104 fprintf(STDERR, "ERROR: %s %s\n", $origin, implode(" ", $args));
105 }
106
107 function onNumeric($origin, $event, array $args) {
108 static $buf = array();
109
110 switch($event) {
111 case RPL_NAMREPLY:
112 if ((list(,, $channel, $users) = $args)) {
113 $buf["names"][$channel] = array_merge((array) $buf["names"][$channel], explode(" ", $users));
114 }
115 break;
116
117 case RPL_ENDOFNAMES:
118 if ((list(, $channel) = $args)) {
119 foreach ($buf["names"][$channel] as $user) {
120 if ($user{0} === "@") {
121 $user = substr($user, 1);
122 }
123 if ($user !== $this->config->nick) {
124 printf("Adding work: WHOIS %s\n", $user);
125 $this->work[] = [
126 [$this, "doWhois"],
127 [$user]
128 ];
129 }
130 }
131 }
132 $buf["names"][$channel] = array();
133 break;
134
135 case RPL_WHOISUSER:
136 if ((list(, $nick, $user, $host, , $real) = $args)) {
137 $this->op(substr($user, 1) ."@" . $host);
138 }
139 break;
140 }
141
142 fprintf(STDERR, "DEBUG: %s %s %s\n", $origin, $this->eventName($event), "<".implode("> <", $args).">");
143 }
144
145 function onConnect($origin, array $args) {
146 list($nick) = $args;
147 $this->connected = true;
148 printf("Connected to %s as %s\n", $origin, $nick);
149 $this->join();
150 }
151
152 function join() {
153 $nopart = array();
154 foreach (array_filter((array) $this->config, "is_array") as $channel => $config) {
155 $nopart[] = $channel;
156 printf("Joining %s...\n", $channel);
157 $this->doJoin($channel, strlen($config["pass"]) ? $config["pass"] : NULL);
158 }
159 foreach (array_diff($this->joined, $nopart) as $channel) {
160 printf("Leaving %s...\n", $channel);
161 $this->doPart($channel);
162 }
163 }
164
165 function op($channel, $origin) {
166 if (preg_match($this->config->{$channel}["oper"], $origin)) {
167 $nick = origin($origin, "nick");
168 printf("Set +o %s\n", $nick);
169 $this->doChannelMode($channel, "+o $nick");
170 }
171 }
172
173 function onPart($origin, array $args) {
174 $nick = origin($origin, "nick");
175
176 if ($nick == $this->config->nick && (list($channel) = $args)) {
177 printf("Left %s\n", $channel);
178 unset($this->joined[array_search($this->joined, $channel, true)]);
179 }
180 }
181
182 function onJoin($origin, array $args) {
183 list($channel) = $args;
184 $nick = origin($origin, "nick");
185
186 if ($nick === $this->config->nick) {
187 printf("Joined %s\n", $channel);
188 $this->joined[] = $channel;
189 } else {
190 printf("%s joined %s\n", $origin, $channel);
191 $this->op($channel, $origin);
192 }
193 }
194
195 function onMode($origin, array $args) {
196 if (count($args) >= 3) {
197 list($channel, $mode, $users) = $args;
198
199 if ($mode === "+o") {
200 printf("Got +o %s\n", $users);
201
202 if (preg_match(sprintf("/\b%s\b/", preg_quote($this->config->nick)), $users)) {
203 $this->doNames($channel);
204 }
205 }
206 }
207 }
208 }