alive = true; $this -> nick = $nick; $this -> username = $username; $this -> realname = $realname; $this -> connection = false; $this -> protocol = new ircprotocol($nick, $username, $realname); $this -> sendbuf = new blockstring($this -> endl); $this -> recvbuf = new blockstring($this -> endl); $this -> reactbuf = new blockstring($this -> endl); $this -> commands = new command_handler(); $this -> userdb = new userdb(); } public function setServer($host, $port){ $this -> host = $host; $this -> port = $port; } public function setAutoReconnect($bool){ $this -> autoreconnect = $bool; } public function setPrefix($prefix){ $this -> prefix = $prefix; } public function addChannels($channels){ $this -> channels = array_merge($this -> channels, $channels); if($this -> login){ foreach($channels as $channel){ $this -> call("join", $channel); } } } public function removeChannels($channels){ foreach($channels as $channel){ unset($this -> channels[array_search($channel, $this -> channels)]); if($this -> login) $this -> call("part", $channel, "Removed ".$channel." from list."); } } public function setSleep($sleep){ $this -> sleep = $sleep * 1000000; } public function clearBuffer(){ $this -> sendbuf -> clear(); $this -> recvbuf -> clear(); $this -> reactbuf -> clear(); } function __destruct(){ $this -> clearBuffer(); if($this -> connection){ $this -> autoreconnect = false; $this -> disconnect(); } unset($this -> recvbuf); unset($this -> sendbuf); unset($this -> reactbuf); unset($this -> commands); unset($this -> userdb); $this -> alive = false; } /* * Connection handling stuff */ public function connect(){ $this -> connection = new fsock($this -> host, $this -> port, 16384, $this -> endl, 5, 0.5); $this -> send($this -> protocol -> auth()); $this -> send($this -> protocol -> nick()); //Wait for being able to join channels while(!$this -> login) $this -> update(); //Join given channels foreach($this -> channels as $channel){ $this -> call("join", $channel); } //Update in order to send all join commands... $this -> update(); } public function send($msg){ if($msg != "") $this -> sendbuf -> addData($msg.$this -> endl); $this -> update(); } public function recv(){ $this -> update(); if(!$line = $this -> recvbuf -> getNextLine()) return false; $recv = $this -> protocol -> parse($line); //add permission level, process-flag and default value for "command" if(isset($recv["nick"])) $recv["level"] = $this -> userdb -> getLevel($recv["nick"]); $recv["processed"] = false; $recv["command"] = false; //If we've got a Query... if($this -> protocol -> checkQuery($recv)){ $recv["processed"] = true; $recv["query"] = true; $recv["command"] = ($recv["msgarr"][0][0] == $this -> prefix) ? substr($recv["msgarr"][0], 1) : $recv["msgarr"][0]; if($code = $this -> commands -> getCode($recv["command"], "query", $recv["level"])){ if($this -> debug) echo "[EVAL] Command: ".$recv["command"]." (query)\n"; if(trim($code) != "" && !is_numeric($code)){ eval($code); } unset($code, $recv["command"]); } }//if query //if command with prefix has been called... if($this -> protocol -> checkCommand($this -> prefix, $recv)){ $recv["processed"] = true; $recv["command"] = $this -> protocol -> getCommand($this -> prefix, $recv); $code = $this -> commands -> getCode($recv["command"], "prefix", $recv["level"]); if(trim($code) != "" && !is_numeric($code)){ if($this -> debug) echo "[EVAL] Command: ".$recv["command"]." (prefix)\n".$code."\n"; eval($code); unset($code, $recv["command"]); } elseif($code == 2){ $this -> call("privmsg", $recv["target"], $recv["nick"].": permission denied! (your level: ".$recv["level"]." < ".$this -> commands -> getLevel($recv["command"]).")"); if(!$this -> userdb -> isActive($recv["nick"]) && $this -> userdb -> isUser($recv["nick"])) $this -> call("notice", $recv["nick"], "You have to identify yourself! (Type ".$this -> prefix."help for further information)"); } elseif($code == 3){ $this -> call("privmsg", $recv["target"], $recv["nick"].": permission denied! (context: ".$this -> commands -> getContext($recv["command"]).")"); } }//if prefix command //If we've got a Channel-Command without trigger...that has NOT been processed before! if(!$recv["processed"] && $this -> protocol -> checkChannel($recv)){ $recv["command"] = $recv["target"]; if($code = $this -> commands -> getCode($recv["command"], "channel", $recv["level"])){ if($this -> debug) echo "[EVAL] Command: ".$recv["command"]." (channel)\n"; eval($code); unset($code, $recv["command"]); $recv["processed"] = true; } }//if channel $recv["command"] = (isset($recv["command"]) && !$recv["processed"]) ? $recv["command"] : ""; return $recv; } /* * Updating recvbuf and flushing sendbuf while checking for incoming pings */ public function update(){ if($this -> connection -> isConnected()){ //Putting recieved stuff into the recv-buffer while($recv = $this -> connection -> recv()){ $this -> reactbuf -> addData($recv); unset($recv); }//recv loop //emergency flood protection $lines = 0; $lines = $this -> reactbuf -> countLines(); if(($lines > 215)){ if($this -> debug) echo "[FLOOD] Houston, we have got a problem! (".$lines." lines at once)\n"; $this -> disconnect(); } //react to stuff while($this -> reactbuf -> gotLine()){ if(!$this -> react($recv = $this -> reactbuf -> getNextLine())) $this -> recvbuf -> addData($recv); } //Sending everything we've got in our buffer while($this -> sendbuf -> gotLine()){ $data = $this -> sendbuf -> getNextLine(); if(($data != $this -> lastline && trim($data) != "") || ($data == $this -> lastline && time() - 10 > $this -> lastlinetime)){//we will never repeat something within 10 seconds if($this -> debug) echo "Sending: '".$data."'\n"; $this -> connection -> send($data); $this -> lastline = $data; $this -> lastlinetime = time(); unset($data); usleep($this -> sleep); } }//send loop //if there is nothing to process and nothing to recieve, we can allow the cpu to have a break. if(!$this -> recvbuf -> gotLine() && !$this -> connection -> gotData()) usleep($this -> sleep); }//if connected else{ if($this -> debug) echo "Connection closed!\n"; $this -> disconnect(); } } public function disconnect(){ if($this -> debug) echo "Disconnecting..."; $this -> clearBuffer(); $this -> login = false; $this -> lastline = ""; $this -> lastlinetime = 0; if($this -> connection){ unset($this -> connection); $this -> connection = false; } if($this -> debug) echo "done.\n"; if($this -> autoreconnect){ sleep(1); if($this -> debug) echo "AutoReconnect enabled. Reconnecting now...\n"; $this -> connect(); if($this -> debug) echo "Reconnect done.\n"; } } /* * Other stuff... */ //Nickchange within runtime public function setNick($nick){ if($this -> nick != $nick){ $this -> nick = $nick; $this -> send($this -> protocol -> setNick($this -> nick)); $this -> update(); } } //Call IRC-Protocol functions (join, part, privmsg,....) and send the result directly public function call(){ $params = func_get_args(); $function = $params[0]; $array = array_slice($params,1); foreach($array as $value) $args[] = addslashes($value); $args = implode("', '",$args); $call = "\$data = \$this -> protocol -> ".$function."('".$args."');"; if($this -> debug) echo "[EVAL] Calling: '".$call."'\n"; eval($call); $this -> send(stripslashes($data)); unset($call, $data); } /* * Reacting to some important stuff */ private function react($recv){ $p = $this -> protocol -> parse($recv); if($this -> login == false && ($p["servermsg"] === true && $p["action"] == "001")) $this -> login = true; //we're logged in if 001 MSG arrives elseif($this -> login == false && ($p["servermsg"] === true && $p["action"] == "433")) $this -> setNick($this -> nick."|".rand(0,9)); //our chosen nick is already in use elseif($p["servermsg"] === true && $p["action"] == "474") $this -> removeChannels(array($p["param"])); //our chosen nick is already in use //if we've got a PING elseif(trim($data = $this -> protocol -> checkPing($recv)) != ""){ $this -> send($data); unset($data); } //check for a serverkick (ERROR) elseif(preg_match("/^ERROR :/", $recv)){ if($this -> debug) echo "Serverkick!\n"; $this -> disconnect(); } elseif($p["action"] == "KICK" && $p["param"] == $this -> nick) $this -> call("join", $p["target"]); //check for being kicked.. elseif($p["action"] == "PART" && $p["nick"] == $this -> nick) $this -> call("join", $p["target"]); //check for being parted.. elseif($p["action"] == "QUIT" || $p["action"] == "PART") $this -> userdb -> logout($p["nick"]); //check for user logout else{ //bot did not react to this line return false; } //bot reacted to this in some way. return true; } /* * Other stuff.... */ //evaluating php-code and return output (WILL CAUSE PROBLEMS WHEN DEBUG-OUTPUT IS ON!) public function eval_php($code){ ob_start(); eval($code); $output = ob_get_contents(); ob_clean(); ob_end_clean(); return $output; } public function eval_sys($cmd){ $p = popen($cmd, "r"); while($data = fgets($p, 8192)){ $result[] = $data; } pclose($p); return $result; } } ?>