From 61ea565f8e0161c0f0f75aac75682941fc2a3611 Mon Sep 17 00:00:00 2001 From: pk910 Date: Tue, 26 Jul 2011 23:49:07 +0200 Subject: [PATCH] added scripting interfaces (addUser, delUser, join, part, kick, privmsg, notice, mode) && added recv_kick, recv_kill, recv_privmsg, recv_notice --- Uplink/EventHandler.interface.php | 6 +- Uplink/P10Formatter.class.php | 9 + Uplink/P10_ModeSets.class.php | 11 +- Uplink/P10_User.class.php | 9 + Uplink/Uplink.class.php | 303 +++++++++++++++++++++++++++++- 5 files changed, 334 insertions(+), 4 deletions(-) diff --git a/Uplink/EventHandler.interface.php b/Uplink/EventHandler.interface.php index 185ee97..b441841 100644 --- a/Uplink/EventHandler.interface.php +++ b/Uplink/EventHandler.interface.php @@ -33,18 +33,22 @@ interface EventHandler { public function event_connect($user, $isBurst); public function event_nick($user, $newNick); + public function event_usermode($user, $modes); public function event_quit($user, $reason); public function event_join($user, $channel, $isBurst); public function event_part($user, $channel, $reason); public function event_kick($user, $target, $channel, $reason); - public function event_mode($user, $channel, $modes); + public function event_chanmode($user, $channel, $modes); public function event_chanmessage($user, $channel, $message); public function event_channotice($user, $channel, $message); public function event_privmessage($user, $channel, $message); public function event_privnotice($user, $channel, $message); + public function event_preparse($from, $command, $arguments); + public function event_unknown_cmd($from, $command, $arguments); + } ?> \ No newline at end of file diff --git a/Uplink/P10Formatter.class.php b/Uplink/P10Formatter.class.php index 39fb704..b5cba3d 100644 --- a/Uplink/P10Formatter.class.php +++ b/Uplink/P10Formatter.class.php @@ -43,6 +43,15 @@ class P10Formatter { "EB" => "{num} EB", "EA" => "{num} EA", "B" => "{num} B %s %s %s", + "Q" => "%s Q :%s", + "D" => "{num} D %s :%s (%s)", + "J" => "%s J %s %s %s", + "K" => "%s K %s %s :%s", + "P" => "%s P %s :%s", + "O" => "%s O %s :%s", + "M" => "%s M %s %s", + "SM" => "%s SM %s %s", + "OM" => "%s OM %s %s", null => null ); diff --git a/Uplink/P10_ModeSets.class.php b/Uplink/P10_ModeSets.class.php index 264a53f..e03521d 100644 --- a/Uplink/P10_ModeSets.class.php +++ b/Uplink/P10_ModeSets.class.php @@ -210,7 +210,7 @@ class P10_ChannelModeSet { foreach(self::$modevalues as $mode => $flag) { if(($this->modeflags & $flag)) { $modestr .= $mode; - if(self::$modevalues[$mode] == self::MODE_WITH_PARAMETER) { + if(self::$modevalues[$mode] == self::MODE_TYPE_B || self::$modevalues[$mode] == self::MODE_TYPE_C) { $paramstr .= " ".$this->modeparams[$mode]; } } @@ -218,6 +218,15 @@ class P10_ChannelModeSet { return $modestr.$paramstr; } + public function hasMode($mode) { + if(!array_key_exists($mode, self::$modevalues)) { + trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING); + continue; + } + $flag = self::$modevalues[$mode]; + return ($this->modeflags & $flag); + } + } class P10_UserModeSet { diff --git a/Uplink/P10_User.class.php b/Uplink/P10_User.class.php index af22f9d..ac235b1 100644 --- a/Uplink/P10_User.class.php +++ b/Uplink/P10_User.class.php @@ -57,6 +57,7 @@ class P10_User { private $numeric; + private $server; private $nick; private $ident; private $host; @@ -84,6 +85,10 @@ class P10_User { return $this->numeric; } + public function getServer() { + return $this->server; + } + public function setNick($nick) { $this->nick = $nick; } @@ -138,6 +143,10 @@ class P10_User { trigger_error("Tried to remove a Channel, that does NOT exist.", E_USER_WARNING); } } + + public function isOnChannel($channel) { + return array_key_exists(strtolower($channel->getName()),$this->channels); + } } ?> \ No newline at end of file diff --git a/Uplink/Uplink.class.php b/Uplink/Uplink.class.php index 7cbc2f3..0585595 100644 --- a/Uplink/Uplink.class.php +++ b/Uplink/Uplink.class.php @@ -59,11 +59,19 @@ require_once("P10_Channel.class.php"); require_once("P10_ModeSets.class.php"); require_once("EventHandler.interface.php"); +$e=1; +define("ERR_NICK_IN_USE", $e++); +define("ERR_INVALID_USER", $e++); +define("ERR_INVALID_CHANNAME", $e++); +define("ERR_NOT_CONNECTED", $e++); +define("ERR_NOT_ON_CHANNEL", $e++); + class Uplink { private $client; private $settings = array(); private $server; private $eventHandler = null; + private $last_local_numeric = 1; const FLAG_P10SESSION = 0x0001; //connection is in P10 mode (server is connected) const FLAG_SECURITY_QUIT = 0x0002; //local connection abort because of security issues @@ -188,6 +196,9 @@ class Uplink { if($cmdPos == 1) $from = $tokens[0]; else $from = null; $arguments = array_slice($tokens, $cmdPos + 1); + if(($this->flags & self::FLAG_P10SESSION) && $this->eventHandler) { + $this->eventHandler->event_preparse($from, strtoupper($tokens[$cmdPos]), $arguments); + } switch(strtoupper($tokens[$cmdPos])) { //pre P10 Session case "PASS": @@ -231,9 +242,23 @@ class Uplink { case "L": $this->recv_part($from, $arguments); break; + case "K": + $this->recv_kick($from, $arguments); + break; + case "D": + $this->recv_kill($from, $arguments); + break; + case "P": + $this->recv_privmsg($from, $arguments); + break; + case "O": + $this->recv_notice($from, $arguments); + break; //default default: //unknown cmd + if($this->eventHandler) + $this->eventHandler->event_unknown_cmd($from, strtoupper($tokens[$cmdPos]), $arguments); break; } } @@ -375,7 +400,7 @@ class Uplink { return; } if($this->eventHandler) - $this->eventHandler->event_quit($user, $args[1]); + $this->eventHandler->event_quit($user, $args[0]); $user->quit($args[0]); } @@ -458,6 +483,82 @@ class Uplink { $channel->partUser($user); } + private function recv_kick($from, $args) { + $user = P10_User::getUserByNum($from); + if($user == null) { + trigger_error("An unknown user tries to kick another user on recv_kick.", E_USER_ERROR); + return; + } + $channel = P10_Channel::getChannelByName($args[0]); + if($channel == null) + $channel = new P10_Channel($args[0]); + $target = P10_User::getUserByNum($args[1]); + if($target == null) { + trigger_error("Someone tries to kick an user that does not exist or was not found on recv_kick.", E_USER_ERROR); + return; + } + if($this->eventHandler) + $this->eventHandler->event_kick($user, $target, $channel, $args[1]); + $channel->partUser($user); + } + + private function recv_kill($from, $args) { + $user = P10_User::getUserByNum($args[0]); + if($user == null) { + trigger_error("Server tries to kill an user that does not exist or was not found on recv_quit.", E_USER_ERROR); + return; + } + if($this->eventHandler) + $this->eventHandler->event_quit($user, "Killed (".$args[1].")"); + $user->quit($args[1]); + } + + private function recv_privmsg($from, $args) { + $user = P10_User::getUserByNum($from); + if($user == null) { + trigger_error("Server tries to send a privmsg from an user that does not exist or was not found on recv_privmsg.", E_USER_ERROR); + return; + } + if($this->eventHandler) { + if($args[0] == "#") { + $channel = P10_Channel::getChannelByName($args[0]); + if($channel == null) + $channel = new P10_Channel($args[0]); + $this->eventHandler->event_chanmessage($user, $channel, $args[1]); + } else { + $targetUser = P10_User::getUserByNum($args[0]); + if($targetUser == null) { + trigger_error("Server tries to send a privmsg to an user that does not exist or was not found on recv_privmsg.", E_USER_ERROR); + return; + } + $this->eventHandler->event_privmessage($user, $targetUser, $args[1]); + } + } + } + + private function recv_notice($from, $args) { + $user = P10_User::getUserByNum($from); + if($user == null) { + trigger_error("Server tries to send a notice from an user that does not exist or was not found on recv_notice.", E_USER_ERROR); + return; + } + if($this->eventHandler) { + if($args[0] == "#") { + $channel = P10_Channel::getChannelByName($args[0]); + if($channel == null) + $channel = new P10_Channel($args[0]); + $this->eventHandler->event_channotice($user, $channel, $args[1]); + } else { + $targetUser = P10_User::getUserByNum($args[0]); + if($targetUser == null) { + trigger_error("Server tries to send a notice to an user that does not exist or was not found on recv_notice.", E_USER_ERROR); + return; + } + $this->eventHandler->event_privnotice($user, $targetUser, $args[1]); + } + } + } + /******************************************************************************************** * SERVER FUNCTIONS * ********************************************************************************************/ @@ -487,7 +588,7 @@ class Uplink { $local_users = true; $sorted_users[$strPrivs][] = $user; } - if(!$local_users) continue; + if(!$local_users && !$channel->getModes()->hasMode("z")) continue; $userStr = ""; foreach($sorted_users['-'] as $user) { if($userStr != "") $userStr.=","; @@ -528,6 +629,204 @@ class Uplink { $this->send("EB"); } + /******************************************************************************************** + * LOCAL USER FUNCTIONS * + ********************************************************************************************/ + + public function addUser($nick, $ident, $host, $ip, $modes, $realname) { + $user = P10_User::getUserByNick($nick); + if($user != null) return ERR_NICK_IN_USE; + $numeric = substr($this->server->getNumeric(),0,2).Numerics::intToNum($this->last_local_numeric, 3); + while(P10_User::getUserByNum($numeric)) { + $this->last_local_numeric++; + $numeric = substr($this->server->getNumeric(),0,2).Numerics::intToNum($this->last_local_numeric, 3); + } + $this->last_local_numeric++; + $user = new P10_User($nick, $numeric, $this->server, time(), $ident, $host, $ip, $realname, $modes); + if(($this->flags & self::FLAG_CONNECTED)) { + $ip = Numerics::numericFromIP($user->getIP()); + $this->send("N", $nick, $user->getConnectTime(), $ident, $host, $user->getModes()->getModeString(), $ip, $numeric, $realname); + } + return $user; + } + + public function delUser($user, $reason) { + if(!is_a($user, "P10_User")) return ERR_INVALID_USER; + if($user->getServer() === $this->server) { + //local user (QUIT) + $user->quit($reason); + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("Q", $user->getNumeric(), $reason); + } else { + //remote user (KILL) + if(!($this->flags & self::FLAG_CONNECTED)) + return ERR_NOT_CONNECTED; + if($this->eventHandler) + $this->eventHandler->event_quit($user, "Killed (".$reason.")"); + $user->quit("Killed (".$reason.")"); + $name = ($this->getSetting('his_name') ? $this->getSetting('his_name') : $this->getSetting('name')); + + $this->send("D", $user->getNumeric(), $name, $reason); + } + } + + public function join($user, $chanName) { + if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) + return ERR_INVALID_USER; + if($chanName[0] != "#") + return ERR_INVALID_CHANNAME; + $channel = P10_Channel::getChannelByName($chanName); + if($channel == null) + $channel = new P10_Channel($chanName); + $channel->joinUser($user); + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("J", $user->getNumeric(), $chanName, time(), 0); + if($this->eventHandler) + $this->eventHandler->event_join($user, $channel, false); + } + + public function part($user, $chanName, $reason) { + if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) + return ERR_INVALID_USER; + if(!((is_string($chanName) && $chanName[0] == "#") || is_a($chanName, "P10_Channel"))) + return ERR_INVALID_CHANNAME; + if(is_a($chanName, "P10_Channel")) + $channel = $chanName; + else + $channel = P10_Channel::getChannelByName($chanName); + if($channel == null) + $channel = new P10_Channel($chanName); + if(!$user->isOnChannel($channel)) + return ERR_NOT_ON_CHANNEL; + if($this->eventHandler) + $this->eventHandler->event_part($user, $channel, $reason); + $channel->partUser($user, $reason); + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("L", $user->getNumeric(), $chanName, $reason); + } + + public function kick($user, $target, $chanName, $reason) { + if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) + return ERR_INVALID_USER; + if(!is_a($target, "P10_User")) + return ERR_INVALID_USER; + if(!((is_string($chanName) && $chanName[0] == "#") || is_a($chanName, "P10_Channel"))) + return ERR_INVALID_CHANNAME; + if(is_a($chanName, "P10_Channel")) + $channel = $chanName; + else + $channel = P10_Channel::getChannelByName($chanName); + if($channel == null) + $channel = new P10_Channel($chanName); + if(!$target->isOnChannel($channel)) + return ERR_NOT_ON_CHANNEL; + if($this->eventHandler) + $this->eventHandler->event_kick($user, $target, $channel, $reason); + $channel->partUser($target, $reason); + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("K", $user->getNumeric(), $chanName, $target->getNumeric(), $reason); + } + + public function privmsg($user, $target, $message) { + if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) + return ERR_INVALID_USER; + if(!is_a($target, "P10_User") && !is_a($target, "P10_Channel") && !(is_string($target) && ($target[0] == "#" || P10_User::getUserByNick($target)))) + return ERR_INVALID_USER; + if(is_a($target, "P10_Channel")) + $targetStr = $target->getName(); + else if(is_a($target, "P10_User")) + $targetStr = $target->getNumeric(); + else if($target[0] == "#") + $targetStr = $target; + else + $targetStr = P10_User::getUserByNick($target)->getNumeric(); + + if($this->eventHandler) { + if($targetStr[0] == "#") { + $channel = P10_Channel::getChannelByName($targetStr); + if($channel == null) + $channel = new P10_Channel($targetStr); + $this->eventHandler->event_chanmessage($user, $channel, $message); + } else { + $targetUser = P10_User::getUserByNum($targetStr); + $this->eventHandler->event_privmessage($user, $targetUser, $message); + } + } + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("P", $user->getNumeric(), $targetStr, $message); + } + + public function notice($user, $target, $message) { + if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) + return ERR_INVALID_USER; + if(!is_a($target, "P10_User") && !is_a($target, "P10_Channel") && !(is_string($target) && ($target[0] == "#" || P10_User::getUserByNick($target)))) + return ERR_INVALID_USER; + if(is_a($target, "P10_Channel")) + $targetStr = $target->getName(); + else if(is_a($target, "P10_User")) + $targetStr = $target->getNumeric(); + else if($target[0] == "#") + $targetStr = $target; + else + $targetStr = P10_User::getUserByNick($target)->getNumeric(); + + if($this->eventHandler) { + if($targetStr[0] == "#") { + $channel = P10_Channel::getChannelByName($targetStr); + if($channel == null) + $channel = new P10_Channel($targetStr); + $this->eventHandler->event_channotice($user, $channel, $message); + } else { + $targetUser = P10_User::getUserByNum($targetStr); + $this->eventHandler->event_privnotice($user, $targetUser, $message); + } + } + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("O", $user->getNumeric(), $targetStr, $message); + } + + public function mode($user, $target, $modes, $force = false) { + if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) + return ERR_INVALID_USER; + if(!is_a($target, "P10_User") && !is_a($target, "P10_Channel") && !(is_string($target) && ($target[0] == "#" || P10_User::getUserByNick($target)))) + return ERR_INVALID_USER; + if(is_a($target, "P10_Channel")) + $targetStr = $target->getName(); + else if(is_a($target, "P10_User")) + $targetStr = $target->getNumeric(); + else if($target[0] == "#") + $targetStr = $target; + else + $targetStr = P10_User::getUserByNick($target)->getNumeric(); + + if($targetStr[0] == "#") { + $channel = P10_Channel::getChannelByName($targetStr); + if($channel == null) + $channel = new P10_Channel($targetStr); + $modes = $channel->getModes()->setModes($modes); + if(($this->flags & self::FLAG_CONNECTED)) + $this->send(($force ? "OM" : "M"), $user->getNumeric(), $targetStr, $modes); + if($this->eventHandler) + $this->eventHandler->event_chanmode(($force ? $this->server : $user), $channel, $modes); + } else { + $targetUser = P10_User::getUserByNum($targetStr); + if($targetUser->getServer() === $this->server) { + //just do it :D + $modes = $targetUser->getModes()->setModes($modes); + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("M", $targetUser->getNumeric(), $targetUser->getNick(), $modes); + if($this->eventHandler) + $this->eventHandler->event_usermode($targetUser, $modes); + } else { + //SVSMODE + if(($this->flags & self::FLAG_CONNECTED)) + $this->send("SM", $user->getNumeric(), $targetUser->getNumeric(), $modes); + } + } + } + + + } ?> \ No newline at end of file -- 2.20.1