Mercurial > hg > udpmsg3
diff simpleircd/simpleircd.php @ 0:dd81c38b513a
Initial commit
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 28 Feb 2011 00:49:07 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simpleircd/simpleircd.php Mon Feb 28 00:49:07 2011 +0100 @@ -0,0 +1,290 @@ +#!/usr/bin/php +<?php +/* Copyright 2010 Ivo Smits <Ivo@UCIS.nl>. All rights reserved. + Redistribution and use in source and binary forms, with or without modification, are + permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + The views and conclusions contained in the software and documentation are those of the + authors and should not be interpreted as representing official policies, either expressed + or implied, of Ivo Smits.*/ + +srand(); + +$listchannels = array(); +$channels = array(); + +$udpmsg = NULL; +$udpmsg_buffer = ''; + +$client_name = NULL; +$client_buffer = ''; + +srand(); + +require 'config.php'; + +client_send(':server NOTICE AUTH :*** Not looking up your hostname, we do not care.'); +client_send(':server NOTICE AUTH :*** Not checking ident, are you serious?'); + +while ($client_name === NULL) { + $line = client_read_line(); + $partsa = explode(' :', $line, 2); + $parts = explode(' ', $partsa[0]); + $command = array_shift(&$parts); + if (count($partsa) > 1) array_push(&$parts, $partsa[1]); + switch (strtoupper($command)) { + case 'NICK': //Nickname change: newnick = $parts[0] + if (!preg_match('/^[a-zA-Z0-9\-_]+$/', $parts[0])) { + client_sendnumeric(432, $parts[0].' :Erroneous nickname'); + } else { + $client_name = $parts[0]; + client_sendnumeric(001, ':Welcome to the Internet Relay Chat Network'); + client_sendnumeric(002, ':Your host is UDPMSG3-IRCD'); + client_sendnumeric(003, ':This server was created some time ago'); + client_sendnumeric(004, 'irc.udpmsg3.local 1.0 + +'); + client_sendnumeric(005, 'NICKLEN=16 CHANNELLEN=16 CHANTYPES=# NETWORK=UDPMSG3 :are supported by this server'); + client_sendnumeric(251, ':There are 1 users and some invisible on a bunch of servers'); + client_sendnumeric(252, '0 :operator(s) online'); + client_sendnumeric(254, count($config['channels']).' :channels formed'); + client_sendnumeric(255, ':I have a bunch of clients and a bunch of servers'); + client_sendnumeric(265, ':Current Local Users: undisclosed'); + client_sendnumeric(266, ':Current Global Users: unknown'); + client_sendnumeric(375, ':- server Message of the Day - '); + client_sendnumeric(372, ':- No message, sorry.'); + client_sendnumeric(376, ':End of /MOTD command.'); + } + case 'USER': + case 'PASS': + break; + default: + client_sendnumeric(421, $command.' :Unknown command'); + } +} + +$udpmsg = stream_socket_client('tcp://'.$config['udpmsg']['host'].':'.$config['udpmsg']['port']); +if (!$udpmsg) { + client_send('ERROR :Could not connect to exchange.'); + die(); +} + +while (TRUE) { + $selwrite = NULL; + $selread = array($udpmsg, STDIN); + $selerror = array($udpmsg, STDIN); + stream_select(&$selread, &$selwrite, &$selerror, 10); + if (in_array($udpmsg, $selerror)) { + fclose($udpmsg); + client_send('ERROR :Lost connection to exchange.'); + die(); + } else { + if (in_array($udpmsg, $selread)) { + if (!udpmsg_read($udpmsg)) { + fclose($udpmsg); + client_send('ERROR :Error in exchange protocol.'); + die(); + } + } + } + if (in_array(STDIN, $selerror)) { + fclose($udpmsg); + client_send('ERROR :Error while reading from client.'); + die(); + } else if (in_array(STDIN, $selread)) { + if (!client_read()) { + fclose($udpmsg); + client_send('ERROR :End of file.'); + die(); + } + } +} + +function udpmsg_read() { + global $channels, $udpmsg, $udpmsg_buffer, $config; + $msg = fread($udpmsg, 1024); + if (!strlen($msg)) return FALSE; + $udpmsg_buffer .= $msg; + while (strlen($udpmsg_buffer) > 2) { + $len = ord($udpmsg_buffer[0]) * 256 + ord($udpmsg_buffer[1]); + if ($len <= 0 || $len > 1024) return FALSE; + if (strlen($udpmsg_buffer) < 2 + $len) break; + $msg = substr($udpmsg_buffer, 2, $len); + $udpmsg_buffer = substr($udpmsg_buffer, 2 + $len); + $parts = explode("\0", $msg); + $ret = array(); + for ($i = 0; $i < count($parts)-1; $i += 2) $ret[$parts[$i]] = $parts[$i+1]; + + if (!isset($ret['CHN']) || !isset($ret['CMD']) || !isset($ret['USR'])) continue; + if (!substr($ret['CHN'], 0, strlen($config['udpmsg']['chprefix']))) continue; + $chn = '#'.substr($ret['CHN'], strlen($config['udpmsg']['chprefix'])); + if (!in_array($chn, $channels)) continue; + if ($ret['CMD'] == 'MSG') { + if (!isset($ret['MSG'])) continue; + $from = preg_replace('/[^a-zA-Z0-9\-_]/', '', $ret['USR']); + if ($config['udpmsg']['nicknetwork'] && isset($ret['NET'])) $from = preg_replace('/[^a-zA-Z0-9\-_]/', '', $ret['NET']).$config['udpmsg']['nickseparator'].$from; + $from = $config['udpmsg']['nickprefix'].$from; + $message = preg_replace('/[\x00\x10-\x13]/', '', $ret['MSG']); + client_send(':'.$from.' PRIVMSG '.$chn.' :'.$message); + } + } + return TRUE; +} + +function udpmsg_send($arr) { + global $udpmsg; + $tmp = array(); + foreach ($arr as $key => $value) { $tmp[] = $key; $tmp[] = $value; } + $tmp[] = ''; + $msg = implode("\0", $tmp); + $len = strlen($msg); + if ($len > 1024) return; + $lens = chr(floor($len / 256)).chr($len % 256); + fwrite($udpmsg, $lens.$msg); +} + +function array_remove(&$arr, $item) { + foreach ($arr as $key => $value) if ($value === $item) unset($arr[$key]); +} + +function client_read() { + global $client_buffer; + $newdata = fread(STDIN, 1024); + if ($newdata === FALSE || !strlen($newdata)) return FALSE; + $client_buffer .= $newdata; + $offset = 0; + $len = strlen($client_buffer); + while ($offset < $len) { + $posa = strpos($client_buffer, "\n", $offset); + $posb = strpos($client_buffer, "\r", $offset); + if ($posa !== FALSE && $posb !== FALSE) { + $pos = min($posa, $posb); + } else if ($posa !== FALSE) { + $pos = $posa; + } else if ($posb !== FALSE) { + $pos = $posb; + } else { + break; + } + $line = substr($client_buffer, $offset, $pos - $offset); + if (strlen($line)) { + if (!client_process($line)) return FALSE; + } + $offset = $pos + 1; + } + if ($offset == $len) { + $client_buffer = ''; + } else if ($offset != 0) { + $client_buffer = substr($client_buffer, $offset); + } + return TRUE; +} + +function client_process($line) { + global $client_name, $config; + $partsa = explode(' :', $line, 2); + $parts = explode(' ', $partsa[0]); + $command = array_shift(&$parts); + if (count($partsa) > 1) array_push(&$parts, $partsa[1]); + switch (strtoupper($command)) { + case 'NICK': + if (!preg_match('/^[a-zA-Z0-9\-_]+$/', $parts[0])) { + client_sendnumeric(432, $parts[0].' :Erroneous nickname'); + } else { + $client_name = $parts[0]; + } + break; + case 'PING': + client_send('PONG :'.$parts[0]); + break; + case 'PRIVMSG': + case 'NOTICE': + $channels = explode(',', $parts[0]); + foreach ($channels as $chn) { + if ($chn[0] == '#') { + if (!in_array($chn, $GLOBALS['channels'])) { + client_sendnumeric(404, $chn.' :Can not send to channel'); + } else { + $umsg = array('CMD' => 'MSG', 'CHN' => $config['udpmsg']['chprefix'].substr($chn, 1), 'MSG' => $parts[1], 'USR' => $client_name, 'DUMMY' => rand(10000, 99999)); + if ($config['udpmsg']['netname']) $umsg['NET'] = $config['udpmsg']['netname']; + udpmsg_send($umsg); + } + } else { + client_sendnumeric(401, $chn.' :No such nickname'); + } + } + break; + case 'JOIN': + $channels = explode(',', $parts[0]); + foreach ($channels as $chn) { + if (!preg_match('/^#[a-zA-Z0-9\-_]+$/', $chn)) { + client_sendnumeric($client, 403, $chn.' :No such channel'); + continue; + } + if (!in_array($chn, $GLOBALS['channels'])) { + client_send(':'.$client_name.'!user@host JOIN :'.$chn); + $GLOBALS['channels'][] = $chn; + } + client_sendnumeric(353, '= '.$chn.' :'.$client_name); + client_sendnumeric(366, $chn.' :End of /NAMES list.'); + } + break; + case 'PART': + client_send(':'.$client_name.'!user@host PART :'.$chn); + array_remove($GLOBALS['channels'], $chn); + break; + case 'QUIT': + return FALSE; + case 'NAMES': + client_sendnumeric(353, '= '.$parts[0].' :'.$client_name); + client_sendnumeric(366, $parts[0].' :End of /NAMES list.'); + break; + case 'LIST': + client_sendnumeric($client, 321, 'Channel :Users Name'); + foreach ($GLOBALS['listchannels'] as $chn) { + client_sendnumeric(322, $chn.' 0 :'); + } + client_sendnumeric(323, 'End of /LIST'); + break; + case 'MODE': + case 'USER': + case 'USERHOST': + break; + default: + client_sendnumeric(421, $command.' :Unknown command'); + } + return TRUE; +} + +function client_sendnumeric($num, $line) { + global $client_name; + client_send(':server '.str_pad($num, 3, '0', STR_PAD_LEFT).' '.$client_name.' '.$line); +} + +function client_send($line) { + print($line."\r\n"); +} + +function client_read_line() { + $line = fgets(STDIN); + if (!strlen($line)) { + client_send('ERROR :End of file.'); + die(); + } + return rtrim($line, "\r\n\x0B"); +}