diff --git a/README.md b/README.md index 941c341..462155c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ DC29BadgeBot =============== -Bot to connect badge to IRC for sharing and validating codes \ No newline at end of file +Bot to connect badge to IRC for sharing and validating codes + +simply git clone this repo + +```` +php bot.php + +``` + +the script will connect to ice.uplinkcorp.net #theSignal and interface with the serial device. \ No newline at end of file diff --git a/README.md b/README.md index 941c341..462155c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ DC29BadgeBot =============== -Bot to connect badge to IRC for sharing and validating codes \ No newline at end of file +Bot to connect badge to IRC for sharing and validating codes + +simply git clone this repo + +```` +php bot.php + +``` + +the script will connect to ice.uplinkcorp.net #theSignal and interface with the serial device. \ No newline at end of file diff --git a/bot.php b/bot.php new file mode 100644 index 0000000..6a26a82 --- /dev/null +++ b/bot.php @@ -0,0 +1,97 @@ +deviceSet($badgeInterface); + $serial->confBaudRate(9600); + $serial->deviceOpen('w+'); + stream_set_timeout($serial->_dHandle, 3); + $serial->sendMessage("\r\n\r\n"."5"."$result"."\r\n"); + $devResponse = $serial->readPort(); + $serial->deviceClose(); + + $toReturn = trim(str_replace("Press ENTER to continue...", "", $devResponse)); + $toReturn = substr($toReturn, -32); + return $toReturn; +} + +function get_own_code(){ + global $badgeInterface; + $serial = new PhpSerial; + $serial->deviceSet($badgeInterface); + $serial->confBaudRate(9600); + $serial->deviceOpen('w+'); + stream_set_timeout($serial->_dHandle, 3); + $serial->sendMessage("\r\n\r\n4\r\n"); + $devResponse = $serial->readPort(); + $serial->deviceClose(); + + $toReturn = trim(str_replace("Invalid Input. Please try again:", "", $devResponse)); + $toReturn = trim(str_replace("Choose an option:", "", $toReturn)); + //echo $toReturn; // DEBUG + $toReturn = substr($toReturn, -32); + return $toReturn; +} + +$rand = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil(8/strlen($x)) )),1,8); + +$socket = fsockopen("ice.uplinkcorp.net", 6667); +// Send auth info +// fputs($socket, "PASS " . $password . "\n"); +fputs($socket, "NICK Badge-" . $rand . "\n"); +fputs($socket, "USER Badge-" . $rand . " 0 * :DC29 Badge Bot\n"); +fputs($socket, "JOIN #theSignal\n"); // Join channel + +// announce self to channel +$myCode = get_own_code(); +fputs($socket, "PRIVMSG #theSignal :!req " . $rand . " " . $myCode . "\n"); + +// Force an endless while +while (1) { + // Continue the rest of the script here + while ($data = fgets($socket, 128)) { + echo $data; + flush(); + + // Separate all data + $ex = explode(' ', $data); + + // Send PONG back to the server + if ($ex[0] == "PING") { + fputs($socket, "PONG " . $ex[1] . "\n"); + } + + // executes chat command + if ($ex[0] != 'PING' && ISSET($ex[3])) { + $command = str_replace(array( + chr(10), + chr(13) + ), '', $ex[3]); + if ($command == ":!req") { + // 4 = bot name, 5 = their code + if(!in_array($ex[4], $collected)){ // not already added their code + $response = get_code($ex[5]); + if(preg_match("/^[0-9A-Fa-f]{32}/", $response)){ // valid code back + fputs($socket, "PRIVMSG #theSignal :!rsp " . $ex[4] . " " . $response . "\n"); + array_push($collected, $ex[4]); // add to replied array + $myCode = get_own_code(); + fputs($socket, "PRIVMSG #theSignal :!req " . $rand . " " . $myCode . "\n"); + + } + } + } + if ($command == ":!rsp") { + if ($ex[4] == $rand){ // response is for this bot + get_code($ex[5]); + } + } + } + } +} +?> diff --git a/README.md b/README.md index 941c341..462155c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ DC29BadgeBot =============== -Bot to connect badge to IRC for sharing and validating codes \ No newline at end of file +Bot to connect badge to IRC for sharing and validating codes + +simply git clone this repo + +```` +php bot.php + +``` + +the script will connect to ice.uplinkcorp.net #theSignal and interface with the serial device. \ No newline at end of file diff --git a/bot.php b/bot.php new file mode 100644 index 0000000..6a26a82 --- /dev/null +++ b/bot.php @@ -0,0 +1,97 @@ +deviceSet($badgeInterface); + $serial->confBaudRate(9600); + $serial->deviceOpen('w+'); + stream_set_timeout($serial->_dHandle, 3); + $serial->sendMessage("\r\n\r\n"."5"."$result"."\r\n"); + $devResponse = $serial->readPort(); + $serial->deviceClose(); + + $toReturn = trim(str_replace("Press ENTER to continue...", "", $devResponse)); + $toReturn = substr($toReturn, -32); + return $toReturn; +} + +function get_own_code(){ + global $badgeInterface; + $serial = new PhpSerial; + $serial->deviceSet($badgeInterface); + $serial->confBaudRate(9600); + $serial->deviceOpen('w+'); + stream_set_timeout($serial->_dHandle, 3); + $serial->sendMessage("\r\n\r\n4\r\n"); + $devResponse = $serial->readPort(); + $serial->deviceClose(); + + $toReturn = trim(str_replace("Invalid Input. Please try again:", "", $devResponse)); + $toReturn = trim(str_replace("Choose an option:", "", $toReturn)); + //echo $toReturn; // DEBUG + $toReturn = substr($toReturn, -32); + return $toReturn; +} + +$rand = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil(8/strlen($x)) )),1,8); + +$socket = fsockopen("ice.uplinkcorp.net", 6667); +// Send auth info +// fputs($socket, "PASS " . $password . "\n"); +fputs($socket, "NICK Badge-" . $rand . "\n"); +fputs($socket, "USER Badge-" . $rand . " 0 * :DC29 Badge Bot\n"); +fputs($socket, "JOIN #theSignal\n"); // Join channel + +// announce self to channel +$myCode = get_own_code(); +fputs($socket, "PRIVMSG #theSignal :!req " . $rand . " " . $myCode . "\n"); + +// Force an endless while +while (1) { + // Continue the rest of the script here + while ($data = fgets($socket, 128)) { + echo $data; + flush(); + + // Separate all data + $ex = explode(' ', $data); + + // Send PONG back to the server + if ($ex[0] == "PING") { + fputs($socket, "PONG " . $ex[1] . "\n"); + } + + // executes chat command + if ($ex[0] != 'PING' && ISSET($ex[3])) { + $command = str_replace(array( + chr(10), + chr(13) + ), '', $ex[3]); + if ($command == ":!req") { + // 4 = bot name, 5 = their code + if(!in_array($ex[4], $collected)){ // not already added their code + $response = get_code($ex[5]); + if(preg_match("/^[0-9A-Fa-f]{32}/", $response)){ // valid code back + fputs($socket, "PRIVMSG #theSignal :!rsp " . $ex[4] . " " . $response . "\n"); + array_push($collected, $ex[4]); // add to replied array + $myCode = get_own_code(); + fputs($socket, "PRIVMSG #theSignal :!req " . $rand . " " . $myCode . "\n"); + + } + } + } + if ($command == ":!rsp") { + if ($ex[4] == $rand){ // response is for this bot + get_code($ex[5]); + } + } + } + } +} +?> diff --git a/php_serial.class.php b/php_serial.class.php new file mode 100644 index 0000000..c7ef423 --- /dev/null +++ b/php_serial.class.php @@ -0,0 +1,638 @@ + for OSX functionality + * Further changes for OSX functionality added by Andrew Hutchings + * default serial device for osx devices is /dev/tty.serial for machines with a built in serial device + * + * @author Rémy Sanchez + * @thanks Aurélien Derouineau for finding how to open serial ports with windows + * @thanks Alec Avedisyan for help and testing with reading + * @copyright under GPL 2 licence + */ +class phpSerial +{ + var $_device = null; + var $_windevice = null; + var $_dHandle = null; + var $_dState = SERIAL_DEVICE_NOTSET; + var $_buffer = ""; + var $_os = ""; + + /** + * This var says if buffer should be flushed by sendMessage (true) or manualy (false) + * + * @var bool + */ + var $autoflush = true; + + /** + * Constructor. Perform some checks about the OS and setserial + * + * @return phpSerial + */ + function phpSerial () + { + setlocale(LC_ALL, "en_US"); + + $sysname = php_uname(); + + if (substr($sysname, 0, 5) === "Linux") + { + $this->_os = "linux"; + + if($this->_exec("stty --version") === 0) + { + register_shutdown_function(array($this, "deviceClose")); + } + else + { + trigger_error("No stty availible, unable to run.", E_USER_ERROR); + } + } + elseif (substr($sysname, 0, 6) === "Darwin") + { + $this->_os = "osx"; + + if($this->_exec("stty") === 0) + { + register_shutdown_function(array($this, "deviceClose")); + } + else + { + trigger_error("No stty availible, unable to run.", E_USER_ERROR); + } + + } + elseif(substr($sysname, 0, 7) === "Windows") + { + $this->_os = "windows"; + register_shutdown_function(array($this, "deviceClose")); + } + else + { + trigger_error("Host OS is neither osx, linux nor windows, unable to run.", E_USER_ERROR); + exit(); + } + } + + // + // OPEN/CLOSE DEVICE SECTION -- {START} + // + + /** + * Device set function : used to set the device name/address. + * -> linux : use the device address, like /dev/ttyS0 + * -> osx : use the device address, like /dev/tty.serial + * -> windows : use the COMxx device name, like COM1 (can also be used + * with linux) + * + * @param string $device the name of the device to be used + * @return bool + */ + function deviceSet ($device) + { + if ($this->_dState !== SERIAL_DEVICE_OPENED) + { + if ($this->_os === "linux") + { + if (preg_match("@^COM(\d+):?$@i", $device, $matches)) + { + $device = "/dev/ttyS" . ($matches[1] - 1); + } + + if ($this->_exec("stty -F " . $device) === 0) + { + $this->_device = $device; + $this->_dState = SERIAL_DEVICE_SET; + return true; + } + } + elseif ($this->_os === "osx") + { + + if (preg_match("@^COM(\d+):?$@i", $device, $matches)) + { + $device = "/dev/ttyS" . ($matches[1] - 1); + } + + if ($this->_exec("stty -f " . $device) === 0) + { + $this->_device = $device; + $this->_dState = SERIAL_DEVICE_SET; + return true; + } + } + elseif ($this->_os === "windows") + { + if (preg_match("@^COM(\d+):?$@i", $device, $matches) and $this->_exec(exec("mode " . $device)) === 0) + { + $this->_windevice = "COM" . $matches[1]; + $this->_device = "\\.\com" . $matches[1]; + $this->_dState = SERIAL_DEVICE_SET; + return true; + } + } + + trigger_error("Specified serial port is not valid", E_USER_WARNING); + return false; + } + else + { + trigger_error("You must close your device before to set an other one", E_USER_WARNING); + return false; + } + } + + /** + * Opens the device for reading and/or writing. + * + * @param string $mode Opening mode : same parameter as fopen() + * @return bool + */ + function deviceOpen ($mode = "r+b") + { + if ($this->_dState === SERIAL_DEVICE_OPENED) + { + trigger_error("The device is already opened", E_USER_NOTICE); + return true; + } + + if ($this->_dState === SERIAL_DEVICE_NOTSET) + { + trigger_error("The device must be set before to be open", E_USER_WARNING); + return false; + } + + if (!preg_match("@^[raw]\+?b?$@", $mode)) + { + trigger_error("Invalid opening mode : ".$mode.". Use fopen() modes.", E_USER_WARNING); + return false; + } + + $this->_dHandle = @fopen($this->_device, $mode); + + if ($this->_dHandle !== false) + { + stream_set_blocking($this->_dHandle, 0); + $this->_dState = SERIAL_DEVICE_OPENED; + return true; + } + + $this->_dHandle = null; + trigger_error("Unable to open the device", E_USER_WARNING); + return false; + } + + /** + * Closes the device + * + * @return bool + */ + function deviceClose () + { + if ($this->_dState !== SERIAL_DEVICE_OPENED) + { + return true; + } + + if (fclose($this->_dHandle)) + { + $this->_dHandle = null; + $this->_dState = SERIAL_DEVICE_SET; + return true; + } + + trigger_error("Unable to close the device", E_USER_ERROR); + return false; + } + + // + // OPEN/CLOSE DEVICE SECTION -- {STOP} + // + + // + // CONFIGURE SECTION -- {START} + // + + /** + * Configure the Baud Rate + * Possible rates : 110, 150, 300, 600, 1200, 2400, 4800, 9600, 38400, + * 57600 and 115200. + * + * @param int $rate the rate to set the port in + * @return bool + */ + function confBaudRate ($rate) + { + if ($this->_dState !== SERIAL_DEVICE_SET) + { + trigger_error("Unable to set the baud rate : the device is either not set or opened", E_USER_WARNING); + return false; + } + + $validBauds = array ( + 110 => 11, + 150 => 15, + 300 => 30, + 600 => 60, + 1200 => 12, + 2400 => 24, + 4800 => 48, + 9600 => 96, + 19200 => 19, + 38400 => 38400, + 57600 => 57600, + 115200 => 115200 + ); + + if (isset($validBauds[$rate])) + { + if ($this->_os === "linux") + { + $ret = $this->_exec("stty -F " . $this->_device . " " . (int) $rate, $out); + } + if ($this->_os === "osx") + { + $ret = $this->_exec("stty -f " . $this->_device . " " . (int) $rate, $out); + } + elseif ($this->_os === "windows") + { + $ret = $this->_exec("mode " . $this->_windevice . " BAUD=" . $validBauds[$rate], $out); + } + else return false; + + if ($ret !== 0) + { + trigger_error ("Unable to set baud rate: " . $out[1], E_USER_WARNING); + return false; + } + } + } + + /** + * Configure parity. + * Modes : odd, even, none + * + * @param string $parity one of the modes + * @return bool + */ + function confParity ($parity) + { + if ($this->_dState !== SERIAL_DEVICE_SET) + { + trigger_error("Unable to set parity : the device is either not set or opened", E_USER_WARNING); + return false; + } + + $args = array( + "none" => "-parenb", + "odd" => "parenb parodd", + "even" => "parenb -parodd", + ); + + if (!isset($args[$parity])) + { + trigger_error("Parity mode not supported", E_USER_WARNING); + return false; + } + + if ($this->_os === "linux") + { + $ret = $this->_exec("stty -F " . $this->_device . " " . $args[$parity], $out); + } + elseif ($this->_os === "osx") + { + $ret = $this->_exec("stty -f " . $this->_device . " " . $args[$parity], $out); + } + else + { + $ret = $this->_exec("mode " . $this->_windevice . " PARITY=" . $parity{0}, $out); + } + + if ($ret === 0) + { + return true; + } + + trigger_error("Unable to set parity : " . $out[1], E_USER_WARNING); + return false; + } + + /** + * Sets the length of a character. + * + * @param int $int length of a character (5 <= length <= 8) + * @return bool + */ + function confCharacterLength ($int) + { + if ($this->_dState !== SERIAL_DEVICE_SET) + { + trigger_error("Unable to set length of a character : the device is either not set or opened", E_USER_WARNING); + return false; + } + + $int = (int) $int; + if ($int < 5) $int = 5; + elseif ($int > 8) $int = 8; + + if ($this->_os === "linux") + { + $ret = $this->_exec("stty -F " . $this->_device . " cs" . $int, $out); + } + elseif ($this->_os === "osx") + { + $ret = $this->_exec("stty -f " . $this->_device . " cs" . $int, $out); + } + else + { + $ret = $this->_exec("mode " . $this->_windevice . " DATA=" . $int, $out); + } + + if ($ret === 0) + { + return true; + } + + trigger_error("Unable to set character length : " .$out[1], E_USER_WARNING); + return false; + } + + /** + * Sets the length of stop bits. + * + * @param float $length the length of a stop bit. It must be either 1, + * 1.5 or 2. 1.5 is not supported under linux and on some computers. + * @return bool + */ + function confStopBits ($length) + { + if ($this->_dState !== SERIAL_DEVICE_SET) + { + trigger_error("Unable to set the length of a stop bit : the device is either not set or opened", E_USER_WARNING); + return false; + } + + if ($length != 1 and $length != 2 and $length != 1.5 and !($length == 1.5 and $this->_os === "linux")) + { + trigger_error("Specified stop bit length is invalid", E_USER_WARNING); + return false; + } + + if ($this->_os === "linux") + { + $ret = $this->_exec("stty -F " . $this->_device . " " . (($length == 1) ? "-" : "") . "cstopb", $out); + } else if ($this->_os === "osx") + { + $ret = $this->_exec("stty -f " . $this->_device . " " . (($length == 1) ? "-" : "") . "cstopb", $out); + } + else + { + $ret = $this->_exec("mode " . $this->_windevice . " STOP=" . $length, $out); + } + + if ($ret === 0) + { + return true; + } + + trigger_error("Unable to set stop bit length : " . $out[1], E_USER_WARNING); + return false; + } + + /** + * Configures the flow control + * + * @param string $mode Set the flow control mode. Availible modes : + * -> "none" : no flow control + * -> "rts/cts" : use RTS/CTS handshaking + * -> "xon/xoff" : use XON/XOFF protocol + * @return bool + */ + function confFlowControl ($mode) + { + if ($this->_dState !== SERIAL_DEVICE_SET) + { + trigger_error("Unable to set flow control mode : the device is either not set or opened", E_USER_WARNING); + return false; + } + + $linuxModes = array( + "none" => "clocal -crtscts -ixon -ixoff", + "rts/cts" => "-clocal crtscts -ixon -ixoff", + "xon/xoff" => "-clocal -crtscts ixon ixoff" + ); + $windowsModes = array( + "none" => "xon=off octs=off rts=on", + "rts/cts" => "xon=off octs=on rts=hs", + "xon/xoff" => "xon=on octs=off rts=on", + ); + + if ($mode !== "none" and $mode !== "rts/cts" and $mode !== "xon/xoff") { + trigger_error("Invalid flow control mode specified", E_USER_ERROR); + return false; + } + + if ($this->_os === "linux") + $ret = $this->_exec("stty -F " . $this->_device . " " . $linuxModes[$mode], $out); + elseif ($this->_os === "osx") + $ret = $this->_exec("stty -f " . $this->_device . " " . $linuxModes[$mode], $out); + else + $ret = $this->_exec("mode " . $this->_windevice . " " . $windowsModes[$mode], $out); + + if ($ret === 0) return true; + else { + trigger_error("Unable to set flow control : " . $out[1], E_USER_ERROR); + return false; + } + } + + /** + * Sets a setserial parameter (cf man setserial) + * NO MORE USEFUL ! + * -> No longer supported + * -> Only use it if you need it + * + * @param string $param parameter name + * @param string $arg parameter value + * @return bool + */ + function setSetserialFlag ($param, $arg = "") + { + if (!$this->_ckOpened()) return false; + + $return = exec ("setserial " . $this->_device . " " . $param . " " . $arg . " 2>&1"); + + if ($return{0} === "I") + { + trigger_error("setserial: Invalid flag", E_USER_WARNING); + return false; + } + elseif ($return{0} === "/") + { + trigger_error("setserial: Error with device file", E_USER_WARNING); + return false; + } + else + { + return true; + } + } + + // + // CONFIGURE SECTION -- {STOP} + // + + // + // I/O SECTION -- {START} + // + + /** + * Sends a string to the device + * + * @param string $str string to be sent to the device + * @param float $waitForReply time to wait for the reply (in seconds) + */ + function sendMessage ($str, $waitForReply = 0.1) + { + $this->_buffer .= $str; + + if ($this->autoflush === true) $this->serialflush(); + + usleep((int) ($waitForReply * 1000000)); + } + + /** + * Reads the port until no new datas are availible, then return the content. + * + * @pararm int $count number of characters to be read (will stop before + * if less characters are in the buffer) + * @return string + */ + function readPort ($count = 0) + { + if ($this->_dState !== SERIAL_DEVICE_OPENED) + { + trigger_error("Device must be opened to read it", E_USER_WARNING); + return false; + } + + if ($this->_os === "linux" || $this->_os === "osx") + { + // Behavior in OSX isn't to wait for new data to recover, but just grabs what's there! + // Doesn't always work perfectly for me in OSX + $content = ""; $i = 0; + + if ($count !== 0) + { + do { + if ($i > $count) $content .= fread($this->_dHandle, ($count - $i)); + else $content .= fread($this->_dHandle, 128); + } while (($i += 128) === strlen($content)); + } + else + { + do { + $content .= fread($this->_dHandle, 128); + } while (($i += 128) === strlen($content)); + } + + return $content; + } + elseif ($this->_os === "windows") + { + /* Do nothing : not implented yet */ + } + + trigger_error("Reading serial port is not implemented for Windows", E_USER_WARNING); + return false; + } + + /** + * Flushes the output buffer + * Renamed from flush for osx compat. issues + * + * @return bool + */ + function serialflush () + { + if (!$this->_ckOpened()) return false; + + if (fwrite($this->_dHandle, $this->_buffer) !== false) + { + $this->_buffer = ""; + return true; + } + else + { + $this->_buffer = ""; + trigger_error("Error while sending message", E_USER_WARNING); + return false; + } + } + + // + // I/O SECTION -- {STOP} + // + + // + // INTERNAL TOOLKIT -- {START} + // + + function _ckOpened() + { + if ($this->_dState !== SERIAL_DEVICE_OPENED) + { + trigger_error("Device must be opened", E_USER_WARNING); + return false; + } + + return true; + } + + function _ckClosed() + { + if ($this->_dState !== SERIAL_DEVICE_CLOSED) + { + trigger_error("Device must be closed", E_USER_WARNING); + return false; + } + + return true; + } + + function _exec($cmd, &$out = null) + { + $desc = array( + 1 => array("pipe", "w"), + 2 => array("pipe", "w") + ); + + $proc = proc_open($cmd, $desc, $pipes); + + $ret = stream_get_contents($pipes[1]); + $err = stream_get_contents($pipes[2]); + + fclose($pipes[1]); + fclose($pipes[2]); + + $retVal = proc_close($proc); + + if (func_num_args() == 2) $out = array($ret, $err); + return $retVal; + } + + // + // INTERNAL TOOLKIT -- {STOP} + // +} +?> \ No newline at end of file