2 /********************************* PHP-P10 ******************************
3 * P10 uplink class by pk910 (c)2011 pk910 *
4 ************************************************************************
7 * PHP-P10 is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with PHP-P10; if not, write to the Free Software Foundation, *
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 ************************************************************************
23 * Uplink/Uplink.class.php
25 * This file contains the basic P10 Protocol handler.
27 ************************************************************************
31 * has to be called after the settings have been set.
34 * loop function that should be calles as many times as possible.
35 * It reads from the socket and BLOCKS the script execution for a
36 * specific time if nothing is received.
38 * void setUplinkHost(String $host, int $port, bool $ssl = false, String $bind = null)
39 * sets the Uplink connection information.
41 * void setLoopTimeout(int $timeout)
42 * sets the maximum time loop() is blocking the script execution.
44 * void setUplinkServer(int $numeric, String $name, String $password, String $description)
45 * sets the own P10 Server information.
47 * void setValidateServer(String $name, String $password)
48 * sets additional security relevant information about the remote server.
50 * void setHISOptions(String $serverName, String $serverDescription String $usermask)
51 * sets the default Account fakehost
53 * void setEventHandler(EventHandler $event_handler)
54 * sets the EventHandlder
56 require_once("Client.class.php");
57 require_once("Numerics.class.php");
58 require_once("P10Formatter.class.php");
59 require_once("P10_Server.class.php");
60 require_once("P10_User.class.php");
61 require_once("P10_Channel.class.php");
62 require_once("P10_ModeSets.class.php");
63 require_once("EventHandler.interface.php");
64 require_once("IPAddr.class.php");
67 define("ERR_NICK_IN_USE", $e++);
68 define("ERR_INVALID_USER", $e++);
69 define("ERR_INVALID_CHANNAME", $e++);
70 define("ERR_NOT_CONNECTED", $e++);
71 define("ERR_NOT_ON_CHANNEL", $e++);
75 private $settings = array();
77 private $eventHandler = null;
78 private $last_local_numeric = 0;
80 const FLAG_P10SESSION = 0x0001; //connection is in P10 mode (server is connected)
81 const FLAG_SECURITY_QUIT = 0x0002; //local connection abort because of security issues
82 const FLAG_NOT_CONNECTABLE = 0x0004; //remote server is not connectable
83 const FLAG_BURST_PENDING = 0x0008; //we still have to burst
84 const FLAG_CONNECTED = 0x0010; //connected and synced (ready)
85 const FLAG_GOT_PASS = 0x0020; //got PASS from the remote Server
88 public function __construct() {
89 $this->client = new Client();
90 $this->setSetting("recv_timeout", 1000);
91 $this->setSetting("his_usermask", "user.NoMask");
94 public function initialize() {
96 trigger_error("Uplink already initialized.", E_USER_ERROR);
99 $self_numeric = $this->getSetting("numeric");
100 $self_name = $this->getSetting("name");
101 $self_description = $this->getSetting("description");
102 if(!$self_numeric || !$self_name) {
103 trigger_error("Server Settings missing.", E_USER_ERROR);
106 $this->server = new P10_Server($self_name, $self_numeric, null, time(), time(), $self_description);
109 public function loop() {
110 if($this->server == null) {
111 trigger_error("Uplink not initialized.", E_USER_ERROR);
114 if(!$this->client->connected()) {
115 if(($this->flags & self::FLAG_P10SESSION)) {
116 //Server got disconnected
117 $this->server->disconnectServer($this->eventHandler, true);
118 $this->flags &= ~self::FLAG_P10SESSION;
120 $host = $this->getSetting("host");
121 $port = $this->getSetting("port");
122 if($host == null || $port == null) {
123 trigger_error("Uplink Settings missing.", E_USER_ERROR);
126 if(($this->flags & self::FLAG_SECURITY_QUIT) || ($this->flags & self::FLAG_NOT_CONNECTABLE)) {
129 $state = $this->client->connect($host, $port, $this->getSetting("bind"), $this->getSetting("ssl"), $this->getSetting("recv_timeout"));
131 usleep($this->getSetting("recv_timeout") / 1000);
132 $this->flags |= self::FLAG_NOT_CONNECTABLE;
136 $this->loginServer();
138 //try to receive new data from the Uplink
139 $lines = $this->client->recv();
140 if($lines == null) return;
141 foreach($lines as $line) {
142 $this->parseLine($line);
146 public function shutdown() {
147 if($this->client->connected()) {
148 if(($this->flags & self::FLAG_P10SESSION)) {
149 $this->send("SQ", "Shutdown requested.");
151 $this->client->disconnect();
155 public function setUplinkHost($host, $port, $ssl = false, $bind = null) {
156 $this->setSetting("host", $host);
157 $this->setSetting("port", $port);
158 $this->setSetting("ssl", $ssl);
159 $this->setSetting("bind", $bind);
162 public function setLoopTimeout($timeout) {
163 $this->setSetting("recv_timeout", $timeout);
166 public function setUplinkServer($numeric, $name, $password, $description) {
167 $this->setSetting("numeric", Numerics::intToNum($numeric, 2));
168 $this->setSetting("name", $name);
169 $this->setSetting("password", $password);
170 $this->setSetting("description", $description);
173 public function setValidateServer($name, $password) {
174 $this->setSetting("their_name", $name);
175 $this->setSetting("their_password", $password);
178 public function setHISOptions($servername, $serverdesc, $usermask) {
179 $this->setSetting("his_name", $servername);
180 $this->setSetting("his_desc", $serverdesc);
181 $this->setSetting("his_usermask", $usermask);
184 public function setEventHandler($event_handler) {
185 if(!is_a($event_handler, "EventHandler")) {
186 trigger_error((is_object($event_handler) ? get_class($event_handler) : gettype($event_handler))." is NOT a valid EventHandler.", E_USER_ERROR);
189 $this->eventHandler = $event_handler;
192 private function setSetting($setting, $value) {
193 $this->settings[$setting] = $value;
196 private function getSetting($setting) {
197 if(array_key_exists($setting, $this->settings)) {
198 return $this->settings[$setting];
204 private function loginServer() {
205 $password = $this->getSetting("password");
206 $this->send("PASS", $password);
207 $this->send("SERVER", $this->server->getName(), $this->server->getStartTime(), $this->server->getLinkTime(), $this->server->getNumeric(), $this->server->getDescription());
210 private function parseLine($line) {
211 $highExplode = explode(" :", $line, 2);
212 $tokens = explode(" ", $highExplode[0]);
213 if(count($highExplode) > 1)
214 $tokens[] = $highExplode[1];
215 $cmdPos = (($this->flags & self::FLAG_P10SESSION) ? 1 : 0);
216 if($cmdPos == 1) $from = $tokens[0];
218 $arguments = array_slice($tokens, $cmdPos + 1);
219 if(($this->flags & self::FLAG_P10SESSION) && $this->eventHandler) {
220 $this->eventHandler->event_preparse($from, strtoupper($tokens[$cmdPos]), $arguments);
222 switch(strtoupper($tokens[$cmdPos])) {
225 $this->recv_pass($from, $arguments);
228 $this->recv_server($from, $arguments);
231 $this->recv_error($from, $arguments);
235 $this->recv_server($from, $arguments);
238 $this->recv_ping($from, $arguments);
241 $this->recv_nick($from, $arguments);
244 $this->recv_end_of_burst($from, $arguments);
247 $this->recv_end_of_burst_ack($from, $arguments);
250 $this->recv_server_quit($from, $arguments);
253 $this->recv_quit($from, $arguments);
256 $this->recv_burst($from, $arguments);
260 $this->recv_join($from, $arguments);
263 $this->recv_part($from, $arguments);
266 $this->recv_kick($from, $arguments);
269 $this->recv_kill($from, $arguments);
272 $this->recv_privmsg($from, $arguments);
275 $this->recv_notice($from, $arguments);
278 $this->recv_whois($from, $arguments);
281 $this->recv_away($from, $arguments);
285 $this->recv_mode($from, $arguments);
290 if($this->eventHandler)
291 $this->eventHandler->event_unknown_cmd($from, strtoupper($tokens[$cmdPos]), $arguments);
296 private function send($command) {
297 if(func_num_args() > 1) {
298 $args = array_slice(func_get_args(), 1);
299 $command = P10Formatter::formatCMD($this->getSetting("numeric"), $command, $args);
301 $command = P10Formatter::formatCMD($this->getSetting("numeric"), $command, array());
303 $this->client->send($command);
306 /********************************************************************************************
307 * INCOMING COMMANDS *
308 ********************************************************************************************/
310 private function recv_pass($from, $args) {
311 $their_pass = $this->getSetting("their_password");
313 if($args[0] != $their_pass) {
315 $this->flags |= self::FLAG_SECURITY_QUIT;
316 $this->send("ERROR", "Incorrect password received.");
317 $this->client->disconnect();
320 $this->flags |= self::FLAG_GOT_PASS;
324 private function recv_error($from, $args) {
325 //we received an error - the socket is dead for us, now
326 //maybe we want to log this, later
327 $this->client->disconnect();
330 private function recv_server($from, $args) {
333 $their_name = $this->getSetting("their_name");
334 if($their_name && $args[0] != $their_name) {
335 $this->flags |= self::FLAG_SECURITY_QUIT;
336 $this->send("ERROR", "Invalid Server name");
337 $this->client->disconnect();
340 if($this->getSetting("their_password") && !($this->flags & self::FLAG_GOT_PASS)) {
341 $this->flags |= self::FLAG_SECURITY_QUIT;
342 $this->send("ERROR", "PASS missing.");
343 $this->client->disconnect();
346 $new_server = new P10_Server($args[0], substr($args[5],0,2), $this->server, $args[2], $args[3], $args[7]);
347 $this->server->addServer($new_server);
348 $this->flags |= self::FLAG_P10SESSION | self::FLAG_BURST_PENDING;
349 if($this->eventHandler)
350 $this->eventHandler->event_newserver($new_server, !($this->flags & self::FLAG_CONNECTED));
352 //another server got a new slave server ^^
353 $server = P10_Server::getServerByNum($from);
354 if($server == null) {
355 trigger_error("Parent Server (".$from.") does not exist or was not found on recv_server.", E_USER_ERROR);
358 $new_server = new P10_Server($args[0], substr($args[5],0,2), $server, $args[2], $args[3], $args[7]);
359 $server->addServer($new_server);
360 if($this->eventHandler)
361 $this->eventHandler->event_newserver($new_server, !($this->flags & self::FLAG_CONNECTED));
365 private function recv_ping($from, $args) {
366 $this->send("Z", $args[0]); //simply PONG
367 P10_Channel::recheckAllChannels();
370 private function recv_nick($from, $args) {
371 if(count($args) <= 2) {
373 $user = P10_User::getUserByNum($from);
375 trigger_error("Server tries to change the nick of an user that does not exist or was not found on recv_nick.", E_USER_ERROR);
378 if($this->eventHandler)
379 $this->eventHandler->event_nick($user, $args[0]);
380 $user->setNick($args[0]);
383 $numeric = $args[count($args)-2];
385 $server = P10_Server::getServerByNum($from);
386 if($server == null) {
387 trigger_error("Server (".$from.") the User (".$nick.") is coming from does not exist or was not found on recv_nick.", E_USER_ERROR);
390 if(substr($numeric,0,2) != $from) {
391 trigger_error("A Server (".$from.") tries to connect a User with an invalid User numeric ('".$numeric."' does not belong to the Server)", E_USER_WARNING);
393 $connect_time = $args[2];
396 $modes = implode(" ",array_slice($args, 5, count($args)-8));
397 $modes = new P10_UserModeSet($modes);
398 $ip = new IPAddr($args[count($args)-3]);
399 $realname = $args[count($args)-1];
400 $user = new P10_User($nick, $numeric, $server, $connect_time, $ident, $host, $ip, $realname, $modes);
401 if($this->eventHandler)
402 $this->eventHandler->event_connect($user, !($this->flags & self::FLAG_CONNECTED));
406 private function recv_end_of_burst($from, $args) {
407 if(($this->flags & self::FLAG_BURST_PENDING)) {
410 $this->flags &= ~self::FLAG_BURST_PENDING;
414 private function recv_end_of_burst_ack($from, $args) {
415 $this->flags |= self::FLAG_CONNECTED;
418 private function recv_server_quit($from, $args) {
419 $server = P10_Server::getServerByName($args[0]);
420 if($server == null) {
421 trigger_error("Server (".$args[0].") not found.", E_USER_ERROR);
424 $server->disconnectServer($this->eventHandler);
427 private function recv_quit($from, $args) {
428 $user = P10_User::getUserByNum($from);
430 trigger_error("Server tries to quit an user that does not exist or was not found on recv_quit.", E_USER_ERROR);
433 if($this->eventHandler)
434 $this->eventHandler->event_quit($user, $args[0]);
435 $user->quit($args[0]);
438 private function recv_burst($from, $args) {
440 $create_time = $args[1];
441 $channel = P10_Channel::getChannelByName($name);
443 $channel = new P10_Channel($name);
444 $channel->setCreateTime($create_time);
445 $modes = $channel->getModes();
446 $userstr = $args[count($args)-1];
447 $modeparamcount = count($args)-3;
448 if($userstr[0] == "%") {
450 $banlist = explode(" ", substr($userstr, 1));
451 foreach($banlist as $ban) {
454 $userstr = $args[count($args)-2];
457 if($userstr[0] == "+") { //MODE String
461 $users = explode(",",$userstr);
462 $isop = false; $isvoice = false;
463 foreach($users as $user) {
464 if($user == "") continue;
465 $uexp = explode(":", $user);
466 if(strlen($uexp[0]) != 5) {
467 trigger_error("burst parse error: '".$uexp[0]."' is not an user numeric.", E_USER_ERROR);
470 if(count($uexp) > 1) {
473 for($i = 0; $i < strlen($uexp[1]); $i++) {
474 if($uexp[1][0] == "@") $isop = true;
475 if($uexp[1][0] == "+") $isvoice = true;
478 $user = P10_User::getUserByNum($uexp[0]);
480 trigger_error("burst parse error: cant find User '".$uexp[0]."'.", E_USER_ERROR);
483 $channel->burstUser($user, $isop, $isvoice);
484 if($this->eventHandler)
485 $this->eventHandler->event_join($user, $channel, true);
487 $modes->parseModes(implode(" ", array_slice($args, 2, $modeparamcount)));
490 private function recv_join($from, $args) {
491 $user = P10_User::getUserByNum($from);
493 trigger_error("Server tries to join an user that does not exist or was not found on recv_join.", E_USER_ERROR);
496 $channel = P10_Channel::getChannelByName($args[0]);
498 $channel = new P10_Channel($args[0]);
499 $channel->joinUser($user);
500 if($this->eventHandler)
501 $this->eventHandler->event_join($user, $channel, false);
504 private function recv_part($from, $args) {
505 $user = P10_User::getUserByNum($from);
507 trigger_error("Server tries to part an user that does not exist or was not found on recv_join.", E_USER_ERROR);
510 $channel = P10_Channel::getChannelByName($args[0]);
512 $channel = new P10_Channel($args[0]);
513 if($this->eventHandler)
514 $this->eventHandler->event_part($user, $channel, $args[1]);
515 $channel->partUser($user);
518 private function recv_kick($from, $args) {
519 $user = P10_User::getUserByNum($from);
521 trigger_error("An unknown user tries to kick another user on recv_kick.", E_USER_ERROR);
524 $channel = P10_Channel::getChannelByName($args[0]);
526 $channel = new P10_Channel($args[0]);
527 $target = P10_User::getUserByNum($args[1]);
528 if($target == null) {
529 trigger_error("Someone tries to kick an user that does not exist or was not found on recv_kick.", E_USER_ERROR);
532 if($this->eventHandler)
533 $this->eventHandler->event_kick($user, $target, $channel, $args[1]);
534 $channel->partUser($user);
537 private function recv_kill($from, $args) {
538 $user = P10_User::getUserByNum($args[0]);
540 trigger_error("Server tries to kill an user that does not exist or was not found on recv_quit.", E_USER_ERROR);
543 if($this->eventHandler)
544 $this->eventHandler->event_quit($user, "Killed (".$args[1].")");
545 $user->quit($args[1]);
548 private function recv_privmsg($from, $args) {
549 $user = P10_User::getUserByNum($from);
551 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);
554 if($this->eventHandler) {
555 if($args[0][0] == "#") {
556 $channel = P10_Channel::getChannelByName($args[0]);
558 $channel = new P10_Channel($args[0]);
559 $this->eventHandler->event_chanmessage($user, $channel, $args[1]);
561 $targetUser = P10_User::getUserByNum($args[0]);
562 if($targetUser == null) {
563 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);
566 $this->eventHandler->event_privmessage($user, $targetUser, $args[1]);
571 private function recv_notice($from, $args) {
572 $user = P10_User::getUserByNum($from);
574 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);
577 if($this->eventHandler) {
578 if($args[0][0] == "#") {
579 $channel = P10_Channel::getChannelByName($args[0]);
581 $channel = new P10_Channel($args[0]);
582 $this->eventHandler->event_channotice($user, $channel, $args[1]);
584 $targetUser = P10_User::getUserByNum($args[0]);
585 if($targetUser == null) {
586 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);
589 $this->eventHandler->event_privnotice($user, $targetUser, $args[1]);
594 private function recv_whois($from, $args) {
595 /* [get] ACAAF W AX :NetworkServ */
596 $fromUser = P10_User::getUserByNum($from);
597 if($fromUser == null) {
598 trigger_error("Server tries to send a whois from an user that does not exist or was not found on recv_whois.", E_USER_ERROR);
601 $users=explode(",",$args[1]);
602 foreach($users as $nick) {
603 $user = P10_User::getUserByNick($nick);
605 $this->send("401", $from, $nick);
608 $nick = $user->getNick();
609 $ident = $user->getIdent();
610 $hostmask = $user->getHost();
611 $modes = $user->getModes();
612 if($modes->hasMode('x')) {
613 if(($fakehost = $modes->hasMode('f'))) {
614 $hostmask = $fakehost;
615 } elseif(($account = $modes->hasMode('r'))) {
616 $hostmask = $account.".".$this->getSetting("his_usermask");
619 $realname = $user->getRealname();
620 $this->send("311", $from , $nick, $ident, $hostmask, $realname);
621 if(((!$modes->hasMode('n') && !$modes->hasMode('k')) || $from == $user->getNumeric()) && count($user->getChannels()) != 0) {
623 foreach($user->getChannels() as $channel) {
624 $cmodes = $channel->getModes();
625 $privs = $channel->getUserPrivs($user);
626 if($cmodes->hasMode("s") && !$fromUser->isOnChannel($channel) && $from != $user->getNumeric()) continue;
627 if($cmodes->hasMode("u") && ($privs & (P10_Channel::USERPRIV_OPED | P10_Channel::USERPRIV_VOICE)) == 0 && $from != $user->getNumeric()) continue;
628 $chanstr = ($channels == "" ? "" : " ");
630 if(($privs & P10_Channel::USERPRIV_OPED)) {
632 } else if(($privs & P10_Channel::USERPRIV_VOICE)) {
635 $chanstr .= $prefix.$channel->getName();
636 if(strlen($channels) + strlen($chanstr) > 450) {
637 $this->send("319", $from, $nick, $channels);
638 $channels = $prefix.$channel->getName();
641 if($channels != "") {
642 $this->send("319", $from, $nick, $channels);
645 if($fromUser->getModes()->hasMode("o") || $from == $user->getNumeric() || !$this->getSetting("his_name")) {
646 $this->send("312", $from, $nick, $user->getServer()->getName(), $user->getServer()->getDescription());
648 $this->send("312", $from, $nick, $this->getSetting("his_name"), $this->getSetting("his_desc"));
650 if($modes->hasMode("o") && (!$modes->hasMode("H") || $fromUser->getModes()->hasMode("o"))) {
651 if($modes->hasMode("S")) {
652 if($modes->hasMode("D"))
653 $this->send("313", $from, $nick, "is a Network Service");
655 $this->send("313", $from, $nick, "is an illegal Network Service - HACKER!");
657 $this->send("313", $from, $nick, "is an IRC Operator");
659 if(($auth = $modes->hasMode("r"))) {
660 $this->send("330", $from, $nick, $auth);
663 $this->send("318", $from, $args[1]);
666 private function recv_away($from, $args) {
667 $user = P10_User::getUserByNum($from);
669 trigger_error("Server tries to send an away command from an user that does not exist or was not found on recv_away.", E_USER_ERROR);
672 if(count($args) > 0) {
673 $user->setAway($args[0]);
675 $user->setAway(null);
679 private function recv_mode($from, $args) {
680 $user = P10_User::getUserByNum($from);
682 trigger_error("Server tries to send a modechange from an user that does not exist or was not found on recv_mode.", E_USER_ERROR);
685 $modes = implode(" ",array_slice($args,1));
686 if($args[0][0] == "#") {
687 $channel = P10_Channel::getChannelByName($args[0]);
689 $channel = new P10_Channel($args[0]);
690 $channel->getModes()->setModes($modes);
691 if($this->eventHandler)
692 $this->eventHandler->event_chanmode($user, $channel, $modes);
694 $targetUser = P10_User::getUserByNick($args[0]);
695 if($targetUser == null) {
696 trigger_error("Server tries to send a mode to an user that does not exist or was not found on recv_mode.", E_USER_ERROR);
699 $targetUser->getModes()->setModes($modes);
700 if($this->eventHandler)
701 $this->eventHandler->event_usermode($targetUser, $modes);
705 /********************************************************************************************
707 ********************************************************************************************/
709 private function burst() {
710 foreach($this->server->getUsers() as $user) {
711 $nick = $user->getNick();
712 $connect_time = $user->getConnectTime();
713 $ident = $user->getIdent();
714 $host = $user->getHost();
715 $modes = $user->getModes()->getModeString();
716 $ip = $user->getIP()->getNumeric();
717 $numeric = $user->getNumeric();
718 $realname = $user->getRealname();
719 $this->send("N", $nick, $connect_time, $ident, $host, $modes, $ip, $numeric, $realname);
721 foreach(P10_Channel::getChannels() as $channel) {
722 $sorted_users = array('ov' => array(), 'o' => array(), 'v' => array(), '-' => array());
723 $local_users = false;
724 foreach($channel->getUsers() as $user) {
725 if(substr($user->getNumeric(), 0, 2) != $this->server->getNumeric()) continue; //skip users that are not on the local server
726 $privs = $channel->getUserPrivs($user);
728 if(($privs & P10_Channel::USERPRIV_OPED)) $strPrivs .= "o";
729 if(($privs & P10_Channel::USERPRIV_VOICE)) $strPrivs .= "v";
730 if($strPrivs == "") $strPrivs = "-";
732 $sorted_users[$strPrivs][] = $user;
734 if(!$local_users) continue;
736 foreach($sorted_users['-'] as $user) {
737 if($userStr != "") $userStr.=",";
738 $userStr .= $user->getNumeric();
740 foreach($sorted_users['ov'] as $i => $user) {
741 if($userStr != "") $userStr.=",";
742 $userStr .= $user->getNumeric();
743 if($i == 0) $userStr .= ":ov";
745 foreach($sorted_users['o'] as $i => $user) {
746 if($userStr != "") $userStr.=",";
747 $userStr .= $user->getNumeric();
748 if($i == 0) $userStr .= ":o";
750 foreach($sorted_users['v'] as $i => $user) {
751 if($userStr != "") $userStr.=",";
752 $userStr .= $user->getNumeric();
753 if($i == 0) $userStr .= ":v";
756 //TODO: Build ban String
758 $modeString = $channel->getModes()->getModeString();
759 if($modeString != "+") {
760 $burstString .= $modeString;
763 if($burstString != "") $burstString .= " ";
764 $burstString .= $userStr;
766 if($banString != "") {
767 if($burstString != "") $burstString .= " ";
768 $burstString .= ":%".$banString;
770 $this->send("B", $channel->getName(), $channel->getCreateTime(), $burstString);
775 /********************************************************************************************
776 * LOCAL USER FUNCTIONS *
777 ********************************************************************************************/
779 public function addUser($nick, $ident, $host, $ip, $modes, $realname) {
780 $user = P10_User::getUserByNick($nick);
781 if($user != null) return ERR_NICK_IN_USE;
782 $numeric = substr($this->server->getNumeric(),0,2).Numerics::intToNum($this->last_local_numeric, 3);
783 while(P10_User::getUserByNum($numeric)) {
784 $this->last_local_numeric++;
785 $numeric = substr($this->server->getNumeric(),0,2).Numerics::intToNum($this->last_local_numeric, 3);
787 $this->last_local_numeric++;
788 $modes = new P10_UserModeSet($modes);
789 $ip = new IPAddr($ip);
790 $user = new P10_User($nick, $numeric, $this->server, time(), $ident, $host, $ip, $realname, $modes);
791 if(($this->flags & self::FLAG_CONNECTED)) {
792 $ip = $user->getIP()->getNumeric();
793 $this->send("N", $nick, $user->getConnectTime(), $ident, $host, $user->getModes()->getModeString(), $ip, $numeric, $realname);
798 public function delUser($user, $reason) {
799 if(!is_a($user, "P10_User")) return ERR_INVALID_USER;
800 if($user->getServer() === $this->server) {
802 $user->quit($reason);
803 if(($this->flags & self::FLAG_CONNECTED))
804 $this->send("Q", $user->getNumeric(), $reason);
807 if(!($this->flags & self::FLAG_CONNECTED))
808 return ERR_NOT_CONNECTED;
809 if($this->eventHandler)
810 $this->eventHandler->event_quit($user, "Killed (".$reason.")");
811 $user->quit("Killed (".$reason.")");
812 $name = ($this->getSetting('his_name') ? $this->getSetting('his_name') : $this->getSetting('name'));
814 $this->send("D", $user->getNumeric(), $name, $reason);
818 public function join($user, $chanName, $privs = 0) {
819 if(!is_a($user, "P10_User") || !($user->getServer() === $this->server))
820 return ERR_INVALID_USER;
821 if($chanName[0] != "#")
822 return ERR_INVALID_CHANNAME;
823 $channel = P10_Channel::getChannelByName($chanName);
825 $channel = new P10_Channel($chanName);
826 $channel->joinUser($user);
827 if(($this->flags & self::FLAG_CONNECTED))
828 $this->send("J", $user->getNumeric(), $chanName, time(), 0);
830 $channel->setUserPrivs($user, $privs);
831 if(($this->flags & self::FLAG_CONNECTED)) {
832 $modestr = "+".(($privs & P10_Channel::USERPRIV_OPED) ? "o" : "").(($privs & P10_Channel::USERPRIV_VOICE) ? "v" : "");
833 $modestr .= (($privs & P10_Channel::USERPRIV_OPED) ? " ".$user->getNumeric() : "");
834 $modestr .= (($privs & P10_Channel::USERPRIV_VOICE) ? " ".$user->getNumeric() : "");
835 $this->send("OM", $user->getNumeric(), $chanName, $modestr);
838 if($this->eventHandler)
839 $this->eventHandler->event_join($user, $channel, false);
842 public function part($user, $chanName, $reason) {
843 if(!is_a($user, "P10_User") || !($user->getServer() === $this->server))
844 return ERR_INVALID_USER;
845 if(!((is_string($chanName) && $chanName[0] == "#") || is_a($chanName, "P10_Channel")))
846 return ERR_INVALID_CHANNAME;
847 if(is_a($chanName, "P10_Channel"))
848 $channel = $chanName;
850 $channel = P10_Channel::getChannelByName($chanName);
852 $channel = new P10_Channel($chanName);
853 if(!$user->isOnChannel($channel))
854 return ERR_NOT_ON_CHANNEL;
855 if($this->eventHandler)
856 $this->eventHandler->event_part($user, $channel, $reason);
857 $channel->partUser($user, $reason);
858 if(($this->flags & self::FLAG_CONNECTED))
859 $this->send("L", $user->getNumeric(), $chanName, $reason);
862 public function kick($user, $target, $chanName, $reason) {
863 if(!is_a($user, "P10_User") || !($user->getServer() === $this->server))
864 return ERR_INVALID_USER;
865 if(!is_a($target, "P10_User"))
866 return ERR_INVALID_USER;
867 if(!((is_string($chanName) && $chanName[0] == "#") || is_a($chanName, "P10_Channel")))
868 return ERR_INVALID_CHANNAME;
869 if(is_a($chanName, "P10_Channel"))
870 $channel = $chanName;
872 $channel = P10_Channel::getChannelByName($chanName);
874 $channel = new P10_Channel($chanName);
875 if(!$target->isOnChannel($channel))
876 return ERR_NOT_ON_CHANNEL;
877 if($this->eventHandler)
878 $this->eventHandler->event_kick($user, $target, $channel, $reason);
879 $channel->partUser($target, $reason);
880 if(($this->flags & self::FLAG_CONNECTED))
881 $this->send("K", $user->getNumeric(), $chanName, $target->getNumeric(), $reason);
884 public function privmsg($user, $target, $message) {
885 if(!is_a($user, "P10_User") || !($user->getServer() === $this->server))
886 return ERR_INVALID_USER;
887 if(!is_a($target, "P10_User") && !is_a($target, "P10_Channel") && !(is_string($target) && ($target[0] == "#" || P10_User::getUserByNick($target))))
888 return ERR_INVALID_USER;
889 if(is_a($target, "P10_Channel"))
890 $targetStr = $target->getName();
891 else if(is_a($target, "P10_User"))
892 $targetStr = $target->getNumeric();
893 else if($target[0] == "#")
894 $targetStr = $target;
896 $targetStr = P10_User::getUserByNick($target)->getNumeric();
898 if($this->eventHandler) {
899 if($targetStr[0] == "#") {
900 $channel = P10_Channel::getChannelByName($targetStr);
902 $channel = new P10_Channel($targetStr);
903 $this->eventHandler->event_chanmessage($user, $channel, $message);
905 $targetUser = P10_User::getUserByNum($targetStr);
906 $this->eventHandler->event_privmessage($user, $targetUser, $message);
909 if(($this->flags & self::FLAG_CONNECTED))
910 $this->send("P", $user->getNumeric(), $targetStr, $message);
913 public function notice($user, $target, $message) {
914 if(!is_a($user, "P10_User") || !($user->getServer() === $this->server))
915 return ERR_INVALID_USER;
916 if(!is_a($target, "P10_User") && !is_a($target, "P10_Channel") && !(is_string($target) && ($target[0] == "#" || P10_User::getUserByNick($target))))
917 return ERR_INVALID_USER;
918 if(is_a($target, "P10_Channel"))
919 $targetStr = $target->getName();
920 else if(is_a($target, "P10_User"))
921 $targetStr = $target->getNumeric();
922 else if($target[0] == "#")
923 $targetStr = $target;
925 $targetStr = P10_User::getUserByNick($target)->getNumeric();
927 if($this->eventHandler) {
928 if($targetStr[0] == "#") {
929 $channel = P10_Channel::getChannelByName($targetStr);
931 $channel = new P10_Channel($targetStr);
932 $this->eventHandler->event_channotice($user, $channel, $message);
934 $targetUser = P10_User::getUserByNum($targetStr);
935 $this->eventHandler->event_privnotice($user, $targetUser, $message);
938 if(($this->flags & self::FLAG_CONNECTED))
939 $this->send("O", $user->getNumeric(), $targetStr, $message);
942 public function mode($user, $target, $modes, $force = false) {
943 if(!is_a($user, "P10_User") || !($user->getServer() === $this->server))
944 return ERR_INVALID_USER;
945 if(!is_a($target, "P10_User") && !is_a($target, "P10_Channel") && !(is_string($target) && ($target[0] == "#" || P10_User::getUserByNick($target))))
946 return ERR_INVALID_USER;
947 if(is_a($target, "P10_Channel"))
948 $targetStr = $target->getName();
949 else if(is_a($target, "P10_User"))
950 $targetStr = $target->getNumeric();
951 else if($target[0] == "#")
952 $targetStr = $target;
954 $targetStr = P10_User::getUserByNick($target)->getNumeric();
956 if($targetStr[0] == "#") {
957 $channel = P10_Channel::getChannelByName($targetStr);
959 $channel = new P10_Channel($targetStr);
960 $modes = $channel->getModes()->setModes($modes, true);
961 if(($this->flags & self::FLAG_CONNECTED))
962 $this->send(($force ? "OM" : "M"), $user->getNumeric(), $targetStr, $modes);
963 if($this->eventHandler)
964 $this->eventHandler->event_chanmode(($force ? $this->server : $user), $channel, $modes);
966 $targetUser = P10_User::getUserByNum($targetStr);
967 if($targetUser->getServer() === $this->server) {
969 $modes = $targetUser->getModes()->setModes($modes, true);
970 if(($this->flags & self::FLAG_CONNECTED))
971 $this->send("M", $targetUser->getNumeric(), $targetUser->getNick(), $modes);
972 if($this->eventHandler)
973 $this->eventHandler->event_usermode($targetUser, $modes);
976 if(($this->flags & self::FLAG_CONNECTED))
977 $this->send("SM", $user->getNumeric(), $targetUser->getNumeric(), $modes);