Mercurial > hg > udpmsg3
comparison simpleircd/simpleircd.php @ 0:dd81c38b513a
Initial commit
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 28 Feb 2011 00:49:07 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:dd81c38b513a |
---|---|
1 #!/usr/bin/php | |
2 <?php | |
3 /* Copyright 2010 Ivo Smits <Ivo@UCIS.nl>. All rights reserved. | |
4 Redistribution and use in source and binary forms, with or without modification, are | |
5 permitted provided that the following conditions are met: | |
6 | |
7 1. Redistributions of source code must retain the above copyright notice, this list of | |
8 conditions and the following disclaimer. | |
9 | |
10 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
11 of conditions and the following disclaimer in the documentation and/or other materials | |
12 provided with the distribution. | |
13 | |
14 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
15 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
16 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR | |
17 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
20 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
21 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
22 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
23 | |
24 The views and conclusions contained in the software and documentation are those of the | |
25 authors and should not be interpreted as representing official policies, either expressed | |
26 or implied, of Ivo Smits.*/ | |
27 | |
28 srand(); | |
29 | |
30 $listchannels = array(); | |
31 $channels = array(); | |
32 | |
33 $udpmsg = NULL; | |
34 $udpmsg_buffer = ''; | |
35 | |
36 $client_name = NULL; | |
37 $client_buffer = ''; | |
38 | |
39 srand(); | |
40 | |
41 require 'config.php'; | |
42 | |
43 client_send(':server NOTICE AUTH :*** Not looking up your hostname, we do not care.'); | |
44 client_send(':server NOTICE AUTH :*** Not checking ident, are you serious?'); | |
45 | |
46 while ($client_name === NULL) { | |
47 $line = client_read_line(); | |
48 $partsa = explode(' :', $line, 2); | |
49 $parts = explode(' ', $partsa[0]); | |
50 $command = array_shift(&$parts); | |
51 if (count($partsa) > 1) array_push(&$parts, $partsa[1]); | |
52 switch (strtoupper($command)) { | |
53 case 'NICK': //Nickname change: newnick = $parts[0] | |
54 if (!preg_match('/^[a-zA-Z0-9\-_]+$/', $parts[0])) { | |
55 client_sendnumeric(432, $parts[0].' :Erroneous nickname'); | |
56 } else { | |
57 $client_name = $parts[0]; | |
58 client_sendnumeric(001, ':Welcome to the Internet Relay Chat Network'); | |
59 client_sendnumeric(002, ':Your host is UDPMSG3-IRCD'); | |
60 client_sendnumeric(003, ':This server was created some time ago'); | |
61 client_sendnumeric(004, 'irc.udpmsg3.local 1.0 + +'); | |
62 client_sendnumeric(005, 'NICKLEN=16 CHANNELLEN=16 CHANTYPES=# NETWORK=UDPMSG3 :are supported by this server'); | |
63 client_sendnumeric(251, ':There are 1 users and some invisible on a bunch of servers'); | |
64 client_sendnumeric(252, '0 :operator(s) online'); | |
65 client_sendnumeric(254, count($config['channels']).' :channels formed'); | |
66 client_sendnumeric(255, ':I have a bunch of clients and a bunch of servers'); | |
67 client_sendnumeric(265, ':Current Local Users: undisclosed'); | |
68 client_sendnumeric(266, ':Current Global Users: unknown'); | |
69 client_sendnumeric(375, ':- server Message of the Day - '); | |
70 client_sendnumeric(372, ':- No message, sorry.'); | |
71 client_sendnumeric(376, ':End of /MOTD command.'); | |
72 } | |
73 case 'USER': | |
74 case 'PASS': | |
75 break; | |
76 default: | |
77 client_sendnumeric(421, $command.' :Unknown command'); | |
78 } | |
79 } | |
80 | |
81 $udpmsg = stream_socket_client('tcp://'.$config['udpmsg']['host'].':'.$config['udpmsg']['port']); | |
82 if (!$udpmsg) { | |
83 client_send('ERROR :Could not connect to exchange.'); | |
84 die(); | |
85 } | |
86 | |
87 while (TRUE) { | |
88 $selwrite = NULL; | |
89 $selread = array($udpmsg, STDIN); | |
90 $selerror = array($udpmsg, STDIN); | |
91 stream_select(&$selread, &$selwrite, &$selerror, 10); | |
92 if (in_array($udpmsg, $selerror)) { | |
93 fclose($udpmsg); | |
94 client_send('ERROR :Lost connection to exchange.'); | |
95 die(); | |
96 } else { | |
97 if (in_array($udpmsg, $selread)) { | |
98 if (!udpmsg_read($udpmsg)) { | |
99 fclose($udpmsg); | |
100 client_send('ERROR :Error in exchange protocol.'); | |
101 die(); | |
102 } | |
103 } | |
104 } | |
105 if (in_array(STDIN, $selerror)) { | |
106 fclose($udpmsg); | |
107 client_send('ERROR :Error while reading from client.'); | |
108 die(); | |
109 } else if (in_array(STDIN, $selread)) { | |
110 if (!client_read()) { | |
111 fclose($udpmsg); | |
112 client_send('ERROR :End of file.'); | |
113 die(); | |
114 } | |
115 } | |
116 } | |
117 | |
118 function udpmsg_read() { | |
119 global $channels, $udpmsg, $udpmsg_buffer, $config; | |
120 $msg = fread($udpmsg, 1024); | |
121 if (!strlen($msg)) return FALSE; | |
122 $udpmsg_buffer .= $msg; | |
123 while (strlen($udpmsg_buffer) > 2) { | |
124 $len = ord($udpmsg_buffer[0]) * 256 + ord($udpmsg_buffer[1]); | |
125 if ($len <= 0 || $len > 1024) return FALSE; | |
126 if (strlen($udpmsg_buffer) < 2 + $len) break; | |
127 $msg = substr($udpmsg_buffer, 2, $len); | |
128 $udpmsg_buffer = substr($udpmsg_buffer, 2 + $len); | |
129 $parts = explode("\0", $msg); | |
130 $ret = array(); | |
131 for ($i = 0; $i < count($parts)-1; $i += 2) $ret[$parts[$i]] = $parts[$i+1]; | |
132 | |
133 if (!isset($ret['CHN']) || !isset($ret['CMD']) || !isset($ret['USR'])) continue; | |
134 if (!substr($ret['CHN'], 0, strlen($config['udpmsg']['chprefix']))) continue; | |
135 $chn = '#'.substr($ret['CHN'], strlen($config['udpmsg']['chprefix'])); | |
136 if (!in_array($chn, $channels)) continue; | |
137 if ($ret['CMD'] == 'MSG') { | |
138 if (!isset($ret['MSG'])) continue; | |
139 $from = preg_replace('/[^a-zA-Z0-9\-_]/', '', $ret['USR']); | |
140 if ($config['udpmsg']['nicknetwork'] && isset($ret['NET'])) $from = preg_replace('/[^a-zA-Z0-9\-_]/', '', $ret['NET']).$config['udpmsg']['nickseparator'].$from; | |
141 $from = $config['udpmsg']['nickprefix'].$from; | |
142 $message = preg_replace('/[\x00\x10-\x13]/', '', $ret['MSG']); | |
143 client_send(':'.$from.' PRIVMSG '.$chn.' :'.$message); | |
144 } | |
145 } | |
146 return TRUE; | |
147 } | |
148 | |
149 function udpmsg_send($arr) { | |
150 global $udpmsg; | |
151 $tmp = array(); | |
152 foreach ($arr as $key => $value) { $tmp[] = $key; $tmp[] = $value; } | |
153 $tmp[] = ''; | |
154 $msg = implode("\0", $tmp); | |
155 $len = strlen($msg); | |
156 if ($len > 1024) return; | |
157 $lens = chr(floor($len / 256)).chr($len % 256); | |
158 fwrite($udpmsg, $lens.$msg); | |
159 } | |
160 | |
161 function array_remove(&$arr, $item) { | |
162 foreach ($arr as $key => $value) if ($value === $item) unset($arr[$key]); | |
163 } | |
164 | |
165 function client_read() { | |
166 global $client_buffer; | |
167 $newdata = fread(STDIN, 1024); | |
168 if ($newdata === FALSE || !strlen($newdata)) return FALSE; | |
169 $client_buffer .= $newdata; | |
170 $offset = 0; | |
171 $len = strlen($client_buffer); | |
172 while ($offset < $len) { | |
173 $posa = strpos($client_buffer, "\n", $offset); | |
174 $posb = strpos($client_buffer, "\r", $offset); | |
175 if ($posa !== FALSE && $posb !== FALSE) { | |
176 $pos = min($posa, $posb); | |
177 } else if ($posa !== FALSE) { | |
178 $pos = $posa; | |
179 } else if ($posb !== FALSE) { | |
180 $pos = $posb; | |
181 } else { | |
182 break; | |
183 } | |
184 $line = substr($client_buffer, $offset, $pos - $offset); | |
185 if (strlen($line)) { | |
186 if (!client_process($line)) return FALSE; | |
187 } | |
188 $offset = $pos + 1; | |
189 } | |
190 if ($offset == $len) { | |
191 $client_buffer = ''; | |
192 } else if ($offset != 0) { | |
193 $client_buffer = substr($client_buffer, $offset); | |
194 } | |
195 return TRUE; | |
196 } | |
197 | |
198 function client_process($line) { | |
199 global $client_name, $config; | |
200 $partsa = explode(' :', $line, 2); | |
201 $parts = explode(' ', $partsa[0]); | |
202 $command = array_shift(&$parts); | |
203 if (count($partsa) > 1) array_push(&$parts, $partsa[1]); | |
204 switch (strtoupper($command)) { | |
205 case 'NICK': | |
206 if (!preg_match('/^[a-zA-Z0-9\-_]+$/', $parts[0])) { | |
207 client_sendnumeric(432, $parts[0].' :Erroneous nickname'); | |
208 } else { | |
209 $client_name = $parts[0]; | |
210 } | |
211 break; | |
212 case 'PING': | |
213 client_send('PONG :'.$parts[0]); | |
214 break; | |
215 case 'PRIVMSG': | |
216 case 'NOTICE': | |
217 $channels = explode(',', $parts[0]); | |
218 foreach ($channels as $chn) { | |
219 if ($chn[0] == '#') { | |
220 if (!in_array($chn, $GLOBALS['channels'])) { | |
221 client_sendnumeric(404, $chn.' :Can not send to channel'); | |
222 } else { | |
223 $umsg = array('CMD' => 'MSG', 'CHN' => $config['udpmsg']['chprefix'].substr($chn, 1), 'MSG' => $parts[1], 'USR' => $client_name, 'DUMMY' => rand(10000, 99999)); | |
224 if ($config['udpmsg']['netname']) $umsg['NET'] = $config['udpmsg']['netname']; | |
225 udpmsg_send($umsg); | |
226 } | |
227 } else { | |
228 client_sendnumeric(401, $chn.' :No such nickname'); | |
229 } | |
230 } | |
231 break; | |
232 case 'JOIN': | |
233 $channels = explode(',', $parts[0]); | |
234 foreach ($channels as $chn) { | |
235 if (!preg_match('/^#[a-zA-Z0-9\-_]+$/', $chn)) { | |
236 client_sendnumeric($client, 403, $chn.' :No such channel'); | |
237 continue; | |
238 } | |
239 if (!in_array($chn, $GLOBALS['channels'])) { | |
240 client_send(':'.$client_name.'!user@host JOIN :'.$chn); | |
241 $GLOBALS['channels'][] = $chn; | |
242 } | |
243 client_sendnumeric(353, '= '.$chn.' :'.$client_name); | |
244 client_sendnumeric(366, $chn.' :End of /NAMES list.'); | |
245 } | |
246 break; | |
247 case 'PART': | |
248 client_send(':'.$client_name.'!user@host PART :'.$chn); | |
249 array_remove($GLOBALS['channels'], $chn); | |
250 break; | |
251 case 'QUIT': | |
252 return FALSE; | |
253 case 'NAMES': | |
254 client_sendnumeric(353, '= '.$parts[0].' :'.$client_name); | |
255 client_sendnumeric(366, $parts[0].' :End of /NAMES list.'); | |
256 break; | |
257 case 'LIST': | |
258 client_sendnumeric($client, 321, 'Channel :Users Name'); | |
259 foreach ($GLOBALS['listchannels'] as $chn) { | |
260 client_sendnumeric(322, $chn.' 0 :'); | |
261 } | |
262 client_sendnumeric(323, 'End of /LIST'); | |
263 break; | |
264 case 'MODE': | |
265 case 'USER': | |
266 case 'USERHOST': | |
267 break; | |
268 default: | |
269 client_sendnumeric(421, $command.' :Unknown command'); | |
270 } | |
271 return TRUE; | |
272 } | |
273 | |
274 function client_sendnumeric($num, $line) { | |
275 global $client_name; | |
276 client_send(':server '.str_pad($num, 3, '0', STR_PAD_LEFT).' '.$client_name.' '.$line); | |
277 } | |
278 | |
279 function client_send($line) { | |
280 print($line."\r\n"); | |
281 } | |
282 | |
283 function client_read_line() { | |
284 $line = fgets(STDIN); | |
285 if (!strlen($line)) { | |
286 client_send('ERROR :End of file.'); | |
287 die(); | |
288 } | |
289 return rtrim($line, "\r\n\x0B"); | |
290 } |