Initial import.
This commit is contained in:
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
class ircbot{
|
||||
|
||||
public $debug = false; //Debugging
|
||||
|
||||
protected $nick;
|
||||
protected $username;
|
||||
protected $realname;
|
||||
|
||||
protected $host;
|
||||
protected $port;
|
||||
|
||||
public $alive; //Bot alive?
|
||||
|
||||
protected $sleep; //How long to wait after sending 1 line
|
||||
|
||||
protected $channels = array(); //Channel-Array
|
||||
|
||||
private $protocol; //IRC-Protocol Handler
|
||||
private $connection; //Fsock-class Handler (false if not connected)
|
||||
private $recvbuf; //RECV-Buffer
|
||||
private $sendbuf; //SEND-Buffer
|
||||
private $reactbuf; //REACT-Buffer (to bypass linebreak errors)
|
||||
|
||||
private $commands; //Command-Handler for additional files
|
||||
private $userdb; //User-Permission-DB
|
||||
|
||||
private $endl = "\r\n"; //ENDL-Marker
|
||||
private $prefix; //Command Prefix
|
||||
|
||||
private $autoreconnect; //Shall the Bot try to reconnect again?
|
||||
private $login = false; //connection successful, we can work if it's true
|
||||
|
||||
private $lastline = ""; //last sent line... (flood protection)
|
||||
private $lastlinetime = 0; //timestamp of last sent line
|
||||
|
||||
|
||||
/*
|
||||
* Class general stuff
|
||||
*/
|
||||
function __construct($nick, $username, $realname){
|
||||
$this -> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user