From 03e505a029d78ab8669580af240c16956fd19828 Mon Sep 17 00:00:00 2001 From: Fbenas Date: Thu, 15 May 2014 13:29:42 +0100 Subject: Inital Commit --- Blatech.ini | 5 ++ Blatech.php | 62 +++++++++++++++ Client.ini | 10 +++ Client.php | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 325 insertions(+) create mode 100644 Blatech.ini create mode 100644 Blatech.php create mode 100644 Client.ini create mode 100644 Client.php diff --git a/Blatech.ini b/Blatech.ini new file mode 100644 index 0000000..9ee7489 --- /dev/null +++ b/Blatech.ini @@ -0,0 +1,5 @@ +;[Command Name] +;command = shell_command +;path = false | /path/to/command +;stdin = true | false +;args = true | false diff --git a/Blatech.php b/Blatech.php new file mode 100644 index 0000000..c1b477e --- /dev/null +++ b/Blatech.php @@ -0,0 +1,62 @@ + + */ +class Blatech +{ + protected $blatech = null; + + /** + * Construct the object loading the config file and storing it + * as an array in the $blatech var + * + * @author Phil Burton + * @param $config String The file and path of the config file + */ + public function __construct($config) + { + $this->blatech = parse_ini_file($config,true); + } + + /** + * Run a shell command and return the result + * + * @author Phil Burton + * @param $message Array The message containing the required commands + * @param $args String The sting of space seperated arguments + * @return String The result of the shell command + * @todo Abstract IRC related information away from this class + */ + public function runCommand($message, $args) + { + $nick = ltrim(explode('!', $message[0])[0],":"); + $channel = $message[2]; + + $msg = explode(" ", ltrim(trim($message[3],"\r\n"), ":!")); + if (!isset($msg[0])) { + return null; + } else { + if (array_key_exists($msg[0], $this->blatech)) { + $command = $this->blatech[$msg[0]]['command']; + $stdin = $this->blatech[$msg[0]]['stdin']; + $cargs = $this->blatech[$msg[0]]['args']; + $path = $this->blatech[$msg[0]]["path"]; + if ($path == true) { + $cd = "cd " . $path . ' && '; + } else { + $cd = ""; + } + if ($stdin == true) { + return explode("\n", shell_exec($cd . 'echo "' . $args . '" | ' . $command))[0]; + } else if ($cargs == true) { + return 'Command Line Arguments Not Supported Yet.'; + } else { + return explode("\n", shell_exec($cd . $command))[0]; + } + } + } + } +} diff --git a/Client.ini b/Client.ini new file mode 100644 index 0000000..2e61b34 --- /dev/null +++ b/Client.ini @@ -0,0 +1,10 @@ +;[config] + +;server = example.com +;port = 12345 +;channel = #channel +;realname = Bot +;username = Bot +;hostname = bla.com +;servername = someserver.com +;pass = PASSWORD for user on network diff --git a/Client.php b/Client.php new file mode 100644 index 0000000..cfd0fca --- /dev/null +++ b/Client.php @@ -0,0 +1,248 @@ + + */ +class Client { + + protected $connected = false; + protected $socket = null; + protected $config = null; + protected $blatech = null; + + /** + * Constructor to load up a config file, and create a socket connection + * and register the client to the IRC server. Then join then the channel + * + * @author Phil Burton + * @param $config array An array of config options + * @todo Use a config object and create a isConfigValid function + */ + public function __construct($config) + { + // Create the client from the given config + $this->config = parse_ini_file($config); + if ($error = $this->isSocket() === true) { + $this->userCommand(); + $ping = $this->nickCommand(); + $this->pongCommand($ping); + $this->connected = true; + $this->identifyCommand(); + $this->joinCommand(); + } else { + var_dump($error); + die(); + } + + } + + /** + * Checks to see if a socket has already been created + * If not, it creates the new socket based on the config + * and then returns true if the socket is created + * + * @author Phil Burton + * @return bool True if socket is created otherwise false + * @todo gracefully return false if the socket didn't get created + */ + protected function isSocket() + { + if (!$this->socket) { + // Try and create socket + if (($this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { + echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; + die(); + } + if (!socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1)) { + echo socket_strerror(socket_last_error($this->socket)); + } + if (socket_connect($this->socket, $this->config['server'], $this->config['port']) === false) { + echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($this->socket)) . "\n"; + } + } + $this->getResponse(); + return true; + } + + /** + * Send the USER command to the IRC server using the config to get the + * required details. + * + * @author Phil Burton + * @todo Create sendCommand function to handle generic message sending + */ + protected function userCommand() + { + socket_write($this->socket, "USER ". $this->config["username"] . ' ' . $this->config['hostname'] . ' ' . $this->config['servername'] . " :" . $this->config['realname'] . "\r\n"); + } + + /** + * Send the NICK command to the IRC server using the config to get the + * required details. + * + * @author Phil Burton + * @todo Create sendCommand function to handle generic message sending + */ + protected function nickCommand() + { + // Set the nick + socket_write($this->socket, "NICK ". $this->config["username"] . "\r\n"); + $response = $this->getResponse(); + var_dump('NICK COMMAND RESPONSE: '); + var_dump($response); + return $response; // save response to use in pong response + } + + /** + * Send the PONG command to the IRC server using the config to get the + * required details. If the ping param is set, then send that too. + * + * @author Phil Burton + * @param @ping String A message to send along with the pong response + * @todo Create sendCommand function to handle generic message sending + * @todo Create better way to handle respones, and log them + */ + protected function pongCommand($ping = null) + { + // Pong the server + if (!$ping) { + socket_write($this->socket, "PONG"); + } else { + socket_write($this->socket, "PONG $ping\r\n"); + } + if (!$this->connected) { + var_dump('PONG COMMAND RESPONSE: '); + $this->getResponse(); + } + } + + /** + * Send a mesage to the IRC server, messaging the nick server to identify + * the client with the config details. + * + * @author Phil Burton + * @todo Create sendCommand function to handle generic message sending + * @todo Create better way to handle respones, and log them + */ + protected function identifyCommand() + { + // Identify the user + socket_write($this->socket, "PRIVMSG ". "nickserv identify " . $this->config["pass"] . "\r\n"); + var_dump('IDENTIFY COMMAND RESPONSE: '); + $this->getResponse(); + } + + /** + * Send a JOIN command to the IRC server to join a channel based on the + * config details + * + * @author Phil Burton + * @todo Create sendCommand function to handle generic message sending + * @todo Create better way to handle respones, and log them + * @todo Find a way to support multiple channels + */ + protected function joinCommand() + { + // Join the channel + socket_write($this->socket, "JOIN ". $this->config["channel"] . "\r\n"); + var_dump('JOIN COMMAND RESPONSE: '); + $this->getResponse(); + } + + /** + * Read the socket, waiting for an incoming message from the IRC + * server. Display memory usage here. Dump and return the response. + * + * @author Phil Burton + * @return String The response from the server + * @todo Create better way to handle respones, and log them + */ + protected function getResponse() + { + var_dump("memory: " . memory_get_usage()/1000 . 'KB'); + $response = ""; + while(true) { + sleep(1); + $response .= socket_read($this->socket,4096); + if ($response == 0) { + echo($response) . "\n"; + return $response; + } + } + } + + /** + * Send a PRIVMSG command to the IRC server to message a channel based on + * the config details. + * + * @author Phil Burton + * @todo Create sendCommand function to handle generic message sending + * @todo Create better way to handle respones, and log them + * @todo Find a way to support multiple channels + * @todo Find a way to support private and channel message sending + */ + public function msgCommand($msg) + { + socket_write($this->socket, "PRIVMSG ". $this->config["channel"] . ' ' . $msg . "\r\n"); + } + + /** + * The main loop of the Client. Constantly listen for incoming messages + * from the IRC server; respond to pings, and look out for bot commands. + * + * @author Phil Burton + * @todo Create sendCommand function to handle generic message sending + * @todo Create better way to handle respones, and log them + * @todo Find a way to support multiple channels + * @todo Find a way to support private and channel message sending + */ + public function loop() + { + while (true) { + $message = explode(" ", $this->getResponse()); + if ($message[0] == 'PING') { + $this->pongCommand($message[1]); + } else { + if (strpos($message[3], ":!") === 0) { + $args = ''; + if(($count = count($message)) > 4) { + for ($i = 4; $i < $count; $i++ ) { + $args .= rtrim($message[$i]) . ' '; + } + $args = rtrim($args); + } + $this->msgCommand($this->blatech->runCommand($message, $args)); + } + } + $message = null; + } + } + + /** + * Check for an existing Blatech object, if it doesn't exist, create it + * with the config path that is passed. + * + * @author Phil Burton + * @return Blatech The Blatech object + */ + public function loadBlatech($config) + { + if (null == $this->blatech) { + include_once("Blatech.php"); + $this->blatech = new Blatech($config); + } + return $this->blatech; + } +} + +// Create a new client object +$client = new Client('Client.ini'); +// Load up the blatech Object +$client->loadBlatech('Blatech.ini'); +// Send a hello command to the channel +$client->msgCommand('In The Rear, With The Gear!'); +// Start the main loop +$client->loop(); + -- cgit v1.2.3