Index: externals/JAXL/.gitignore =================================================================== --- /dev/null +++ externals/JAXL/.gitignore @@ -0,0 +1,6 @@ +.buildpath +.project +.jaxl +.pydevproject +.settings/ +docs/_build Index: externals/JAXL/LICENSE =================================================================== --- /dev/null +++ externals/JAXL/LICENSE @@ -0,0 +1,33 @@ +Jaxl (Jabber XMPP Library) + +Copyright (c) 2009-2012, Abhinav Singh . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +Neither the name of Abhinav Singh nor the names of his +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. Index: externals/JAXL/README.md =================================================================== --- /dev/null +++ externals/JAXL/README.md @@ -0,0 +1,30 @@ +Jaxl v3.x: +----------- +Jaxl v3.x is a successor of v2.x (and is NOT backward compatible), +carrying a lot of code from v2.x while throwing away the ugly parts. +A lot of components have been re-written keeping in mind the feedback from +the developer community over the last 4 years. Also Jaxl shares a few +philosophies from my experience with erlang and python languages. + +Jaxl is an asynchronous, non-blocking I/O, event based PHP library +for writing custom TCP/IP client and server implementations. +From it's previous versions, library inherits a full blown stable support +for [XMPP protocol stack](https://github.com/abhinavsingh/JAXL/tree/v3.x/xmpp). +In v3.0, support for [HTTP protocol stack](https://github.com/abhinavsingh/JAXL/tree/v3.x/http) +has also been added. + +At the heart of every protocol stack sits the [Core stack](https://github.com/abhinavsingh/JAXL/tree/v3.x/core). +It contains all the building blocks for everything that we aim to do with Jaxl library. +Both XMPP and HTTP protocol stacks are written on top of the Core stack. +Infact the source code of protocol implementations knows nothing +about the standard (inbuilt) PHP socket and stream methods. + +[Examples](https://github.com/abhinavsingh/JAXL/tree/v3.x/examples/) + +[Documentation](http://jaxl.readthedocs.org/) + +[Group and Mailing List](https://groups.google.com/forum/#!forum/jaxl) + +[Create a bug/issue](https://github.com/abhinavsingh/JAXL/issues/new) + +[Author](http://abhinavsingh.com/) Index: externals/JAXL/composer.json =================================================================== --- /dev/null +++ externals/JAXL/composer.json @@ -0,0 +1,23 @@ +{ + "name": "abhinavsingh/jaxl", + "type": "library", + "description": "Jaxl - Async, Non-Blocking, Event based Networking Library in PHP.", + "keywords": ["xmpp", "jabber", "http", "asynchronous", "non blocking", "event loop", "php", "jaxl", "abhinavsingh"], + "homepage": "http://jaxl.readthedocs.org/en/latest/index.html", + "license": "MIT", + + "authors": [ + { + "name": "Abhinavsingh", + "homepage": "https://abhinavsingh.com/" + } + ], + + "require": { + "php": ">=5.2.4" + }, + + "autoload": { + "files": ["jaxl.php"] + } +} \ No newline at end of file Index: externals/JAXL/core/README.md =================================================================== --- /dev/null +++ externals/JAXL/core/README.md @@ -0,0 +1,17 @@ +Jaxl Core Stack: +---------------- +Core stack implementation includes: + +* JAXLLoop - Event Loop +* JAXLClock - Time and Periodic Job server +* JAXLSocketClient - Generic Non-Blocking Socket Client +* JAXLSocketServer - Generic Non-Blocking Socket Server +* JAXLCli - Generic Non-Blocking Command Line Interface +* JAXLEvent - Generic Event Emitter +* JAXLFsm - Generic Finite State Machine +* JAXLLogger - Logging utilities +* JAXLPipe - Bidirectional Communication between Processes using Unix Pipes +* JAXLSock5 - SOCKS5 RFC Implementation +* JAXLXml - Light Weight XML Representation +* JAXLXmlStream - Streaming XML Parser +* JAXLException - Error, Exception and Shutdown handler \ No newline at end of file Index: externals/JAXL/core/jaxl_cli.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_cli.php @@ -0,0 +1,97 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_loop.php'; + +class JAXLCli { + + public static $counter = 0; + private $in = null; + + private $quit_cb = null; + private $recv_cb = null; + private $recv_chunk_size = 1024; + + public function __construct($recv_cb=null, $quit_cb=null) { + $this->recv_cb = $recv_cb; + $this->quit_cb = $quit_cb; + + // catch read event on stdin + $this->in = fopen('php://stdin', 'r'); + stream_set_blocking($this->in, false); + JAXLLoop::watch($this->in, array( + 'read' => array(&$this, 'on_read_ready') + )); + } + + public function __destruct() { + @fclose($this->in); + } + + public function stop() { + JAXLLoop::unwatch($this->in, array( + 'read' => true + )); + } + + public function on_read_ready($in) { + $raw = @fread($in, $this->recv_chunk_size); + + if(ord($raw) == 10) { + // enter key + JAXLCli::prompt(false); + return; + } + else if(trim($raw) == 'quit') { + $this->stop(); + $this->in = null; + if($this->quit_cb) call_user_func($this->quit_cb); + return; + } + + if($this->recv_cb) call_user_func($this->recv_cb, $raw); + } + + public static function prompt($inc=true) { + if($inc) ++self::$counter; + echo "jaxl ".self::$counter."> "; + } + +} + +?> Index: externals/JAXL/core/jaxl_clock.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_clock.php @@ -0,0 +1,126 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +class JAXLClock { + + // current clock time in microseconds + private $tick = 0; + + // current Unix timestamp with microseconds + public $time = null; + + // scheduled jobs + public $jobs = array(); + + public function __construct() { + $this->time = microtime(true); + } + + public function __destruct() { + _info("shutting down clock server..."); + } + + public function tick($by=null) { + // update clock + if($by) { + $this->tick += $by; + $this->time += $by / pow(10,6); + } + else { + $time = microtime(true); + $by = $time - $this->time; + $this->tick += $by * pow(10, 6); + $this->time = $time; + } + + // run scheduled jobs + foreach($this->jobs as $ref=>$job) { + if($this->tick >= $job['scheduled_on'] + $job['after']) { + //_debug("running job#".($ref+1)." at tick ".$this->tick.", scheduled on ".$job['scheduled_on']." after ".$job['after'].", periodic ".$job['is_periodic']); + call_user_func($job['cb'], $job['args']); + if(!$job['is_periodic']) { + unset($this->jobs[$ref]); + } + else { + $job['scheduled_on'] = $this->tick; + $job['runs']++; + $this->jobs[$ref] = $job; + } + } + } + } + + // calculate execution time of callback + public function tc($callback, $args=null) { + + } + + // callback after $time microseconds + public function call_fun_after($time, $callback, $args=null) { + $this->jobs[] = array( + 'scheduled_on' => $this->tick, + 'after' => $time, + 'cb' => $callback, + 'args' => $args, + 'is_periodic' => false, + 'runs' => 0 + ); + return sizeof($this->jobs); + } + + // callback periodically after $time microseconds + public function call_fun_periodic($time, $callback, $args=null) { + $this->jobs[] = array( + 'scheduled_on' => $this->tick, + 'after' => $time, + 'cb' => $callback, + 'args' => $args, + 'is_periodic' => true, + 'runs' => 0 + ); + return sizeof($this->jobs); + } + + // cancel a previously scheduled callback + public function cancel_fun_call($ref) { + unset($this->jobs[$ref-1]); + } + +} + +?> Index: externals/JAXL/core/jaxl_event.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_event.php @@ -0,0 +1,121 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +/** + * following kind of events are possible: + * 1) hook i.e. if a callback for such an event is registered, calling function is responsible for the workflow from their on + * 2) filter i.e. calling function will manipulate passed arguments and modified arguments will be passed to next chain of filter + * + * As a rule of thumb, only 1 hook can be registered for an event, while more than 1 filter is allowed for an event + * hook and filter both cannot be applied on an event + * + * @author abhinavsingh + * + */ +class JAXLEvent { + + protected $common = array(); + public $reg = array(); + + public function __construct($common) { + $this->common = $common; + } + + public function __destruct() { + + } + + // add callback on a event + // returns a reference to be used while deleting callback + // callback'd method must return TRUE to be persistent + // if none returned or FALSE, callback will be removed automatically + public function add($ev, $cb, $pri) { + if(!isset($this->reg[$ev])) + $this->reg[$ev] = array(); + + $ref = sizeof($this->reg[$ev]); + $this->reg[$ev][] = array($pri, $cb); + return $ev."-".$ref; + } + + // emit event to notify registered callbacks + // is a pqueue required here for performance enhancement + // in case we have too many cbs on a specific event? + public function emit($ev, $data=array()) { + $data = array_merge($this->common, $data); + $cbs = array(); + + if(!isset($this->reg[$ev])) return $data; + + foreach($this->reg[$ev] as $cb) { + if(!isset($cbs[$cb[0]])) + $cbs[$cb[0]] = array(); + $cbs[$cb[0]][] = $cb[1]; + } + + foreach($cbs as $pri => $cb) { + foreach($cb as $c) { + $ret = call_user_func_array($c, $data); + // this line is for fixing situation where callback function doesn't return an array type + // in such cases next call of call_user_func_array will report error since $data is not an array type as expected + // things will change in future, atleast put the callback inside a try/catch block + // here we only check if there was a return, if yes we update $data with return value + // this is bad design, need more thoughts, should work as of now + if($ret) $data = $ret; + } + } + + unset($cbs); + return $data; + } + + // remove previous registered callback + public function del($ref) { + $ref = explode("-", $ref); + unset($this->reg[$ref[0]][$ref[1]]); + } + + public function exists($ev) { + $ret = isset($this->reg[$ev]); + //_debug("event ".$ev." callback ".($ret ? "exists" : "do not exists")); + return $ret; + } + +} + +?> Index: externals/JAXL/core/jaxl_exception.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_exception.php @@ -0,0 +1,94 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +error_reporting(E_ALL | E_STRICT); + +/** + * + * @author abhinavsingh + */ +class JAXLException extends Exception { + + public function __construct($message = null, $code = null, $file = null, $line = null) { + _notice("got jaxl exception construct with $message, $code, $file, $line"); + if($code === null) { + parent::__construct($message); + } + else { + parent::__construct($message, $code); + } + + if($file !== null) { + $this->file = $file; + } + + if($line !== null) { + $this->line = $line; + } + } + + public static function error_handler($errno, $error, $file, $line, $vars) { + _debug("error handler called with $errno, $error, $file, $line"); + if($errno === 0 || ($errno & error_reporting()) === 0) { + return; + } + + throw new JAXLException($error, $errno, $file, $line); + } + + public static function exception_handler($e) { + _debug("exception handler catched ".json_encode($e)); + + // TODO: Pretty print backtrace + //print_r(debug_backtrace()); + } + + public static function shutdown_handler() { + try { + _debug("got shutdown handler"); + if(null !== ($error = error_get_last())) { + throw new JAXLException($error['message'], $error['type'], $error['file'], $error['line']); + } + } + catch(Exception $e) { + _debug("shutdown handler catched with exception ".json_encode($e)); + } + } +} + +?> Index: externals/JAXL/core/jaxl_fsm.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_fsm.php @@ -0,0 +1,84 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +abstract class JAXLFsm { + + protected $state = null; + + // abstract method + abstract public function handle_invalid_state($r); + + public function __construct($state) { + $this->state = $state; + } + + // returned value from state callbacks can be: + // 1) array() <-- is_callable method + // 2) array([0]=>'new_state', [1]=>'return value for current callback') <-- is_not_callable method + // 3) array([0]=>'new_state') + // 4) 'new_state' + // + // for case 1) new state will be an array + // for other cases new state will be a string + public function __call($event, $args) { + if($this->state) { + // call state method + _debug("calling state handler '".(is_array($this->state) ? $this->state[1] : $this->state)."' for incoming event '".$event."'"); + $call = is_callable($this->state) ? $this->state : (method_exists($this, $this->state) ? array(&$this, $this->state): $this->state); + $r = call_user_func($call, $event, $args); + + // 4 cases of possible return value + if(is_callable($r)) $this->state = $r; + else if(is_array($r) && sizeof($r) == 2) list($this->state, $ret) = $r; + else if(is_array($r) && sizeof($r) == 1) $this->state = $r[0]; + else if(is_string($r)) $this->state = $r; + else $this->handle_invalid_state($r); + _debug("current state '".(is_array($this->state) ? $this->state[1] : $this->state)."'"); + + // return case + if(!is_callable($r) && is_array($r) && sizeof($r) == 2) + return $ret; + } + else { + _debug("invalid state found, nothing called for event ".$event.""); + } + } + +} + +?> Index: externals/JAXL/core/jaxl_logger.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_logger.php @@ -0,0 +1,92 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// log level +define('JAXL_ERROR', 1); +define('JAXL_WARNING', 2); +define('JAXL_NOTICE', 3); +define('JAXL_INFO', 4); +define('JAXL_DEBUG', 5); + +// generic global logging shortcuts for different level of verbosity +function _error($msg) { JAXLLogger::log($msg, JAXL_ERROR); } +function _warning($msg) { JAXLLogger::log($msg, JAXL_WARNING); } +function _notice($msg) { JAXLLogger::log($msg, JAXL_NOTICE); } +function _info($msg) { JAXLLogger::log($msg, JAXL_INFO); } +function _debug($msg) { JAXLLogger::log($msg, JAXL_DEBUG); } + +// generic global terminal output colorize method +// finally sends colorized message to terminal using error_log/1 +// this method is mainly to escape $msg from file:line and time +// prefix done by _debug, _error, ... methods +function _colorize($msg, $verbosity) { error_log(JAXLLogger::colorize($msg, $verbosity)); } + +class JAXLLogger { + + public static $level = JAXL_DEBUG; + public static $path = null; + public static $max_log_size = 1000; + + protected static $colors = array( + 1 => 31, // error: red + 2 => 34, // warning: blue + 3 => 33, // notice: yellow + 4 => 32, // info: green + 5 => 37 // debug: white + ); + + public static function log($msg, $verbosity=1) { + if($verbosity <= self::$level) { + $bt = debug_backtrace(); array_shift($bt); $callee = array_shift($bt); + $msg = basename($callee['file'], '.php').":".$callee['line']." - ".@date('Y-m-d H:i:s')." - ".$msg; + + $size = strlen($msg); + if($size > self::$max_log_size) $msg = substr($msg, 0, self::$max_log_size) . ' ...'; + + if(isset(self::$path)) error_log($msg . PHP_EOL, 3, self::$path); + else error_log(self::colorize($msg, $verbosity)); + } + } + + public static function colorize($msg, $verbosity) { + return "\033[".self::$colors[$verbosity]."m".$msg."\033[0m"; + } + +} + +?> Index: externals/JAXL/core/jaxl_loop.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_loop.php @@ -0,0 +1,159 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_logger.php'; +require_once JAXL_CWD.'/core/jaxl_clock.php'; + +/** + * + * Enter description here ... + * @author abhinavsingh + * + */ +class JAXLLoop { + + public static $clock = null; + + private static $is_running = false; + private static $active_read_fds = 0; + private static $active_write_fds = 0; + + private static $read_fds = array(); + private static $read_cbs = array(); + private static $write_fds = array(); + private static $write_cbs = array(); + + public static $secs = 0; + public static $usecs = 30000; + + private function __construct() {} + private function __clone() {} + + public static function watch($fd, $opts) { + if(isset($opts['read'])) { + $fdid = (int) $fd; + self::$read_fds[$fdid] = $fd; + self::$read_cbs[$fdid] = $opts['read']; + ++self::$active_read_fds; + } + + if(isset($opts['write'])) { + $fdid = (int) $fd; + self::$write_fds[$fdid] = $fd; + self::$write_cbs[$fdid] = $opts['write']; + ++self::$active_write_fds; + } + + _debug("active read fds: ".self::$active_read_fds.", write fds: ".self::$active_write_fds); + } + + public static function unwatch($fd, $opts) { + if(isset($opts['read'])) { + $fdid = (int) $fd; + if(isset(self::$read_fds[$fdid])) { + unset(self::$read_fds[$fdid]); + unset(self::$read_cbs[$fdid]); + --self::$active_read_fds; + } + } + + if(isset($opts['write'])) { + $fdid = (int) $fd; + if(isset(self::$write_fds[$fdid])) { + unset(self::$write_fds[$fdid]); + unset(self::$write_cbs[$fdid]); + --self::$active_write_fds; + } + } + + _debug("active read fds: ".self::$active_read_fds.", write fds: ".self::$active_write_fds); + } + + public static function run() { + if(!self::$is_running) { + self::$is_running = true; + self::$clock = new JAXLClock(); + + while((self::$active_read_fds + self::$active_write_fds) > 0) + self::select(); + + _debug("no more active fd's to select"); + self::$is_running = false; + } + } + + public static function select() { + $read = self::$read_fds; + $write = self::$write_fds; + $except = null; + + $changed = @stream_select($read, $write, $except, self::$secs, self::$usecs); + if($changed === false) { + _error("error in the event loop, shutting down..."); + /*foreach(self::$read_fds as $fd) { + if(is_resource($fd)) + print_r(stream_get_meta_data($fd)); + }*/ + exit; + } + else if($changed > 0) { + // read callback + foreach($read as $r) { + $fdid = array_search($r, self::$read_fds); + if(isset(self::$read_fds[$fdid])) + call_user_func(self::$read_cbs[$fdid], self::$read_fds[$fdid]); + } + + // write callback + foreach($write as $w) { + $fdid = array_search($w, self::$write_fds); + if(isset(self::$write_fds[$fdid])) + call_user_func(self::$write_cbs[$fdid], self::$write_fds[$fdid]); + } + + self::$clock->tick(); + } + else if($changed === 0) { + //_debug("nothing changed while selecting for read"); + self::$clock->tick((self::$secs * pow(10,6)) + self::$usecs); + } + } + +} + +?> Index: externals/JAXL/core/jaxl_pipe.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_pipe.php @@ -0,0 +1,115 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_event.php'; +require_once JAXL_CWD.'/core/jaxl_loop.php'; + +/** + * bidirectional communication pipes for processes + * + * This is how this will be (when complete): + * $pipe = new JAXLPipe() will return an array of size 2 + * $pipe[0] represents the read end of the pipe + * $pipe[1] represents the write end of the pipe + * + * Proposed functionality might even change (currently consider this as experimental) + * + * @author abhinavsingh + * + */ +class JAXLPipe { + + protected $perm = 0600; + + protected $recv_cb = null; + protected $fd = null; + protected $client = null; + + public $name = null; + + public function __construct($name, $read_cb=null) { + $pipes_folder = JAXL_CWD.'/.jaxl/pipes'; + if(!is_dir($pipes_folder)) mkdir($pipes_folder); + + $this->ev = new JAXLEvent(); + $this->name = $name; + $this->read_cb = $read_cb; + + $pipe_path = $this->get_pipe_file_path(); + if(!file_exists($pipe_path)) { + posix_mkfifo($pipe_path, $this->perm); + $this->fd = fopen($pipe_path, 'r+'); + if(!$this->fd) { + _error("unable to open pipe"); + } + else { + _debug("pipe opened using path $pipe_path"); + _notice("Usage: $ echo 'Hello World!' > $pipe_path"); + + $this->client = new JAXLSocketClient(); + $this->client->connect($this->fd); + $this->client->set_callback(array(&$this, 'on_data')); + } + } + else { + _error("pipe with name $name already exists"); + } + } + + public function __destruct() { + @fclose($this->fd); + @unlink($this->get_pipe_file_path()); + _debug("unlinking pipe file"); + } + + public function get_pipe_file_path() { + return JAXL_CWD.'/.jaxl/pipes/jaxl_'.$this->name.'.pipe'; + } + + public function set_callback($recv_cb) { + $this->recv_cb = $recv_cb; + } + + public function on_data($data) { + // callback + if($this->recv_cb) call_user_func($this->recv_cb, $data); + } + +} + +?> Index: externals/JAXL/core/jaxl_sock5.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_sock5.php @@ -0,0 +1,128 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_socket_client.php'; + +/** + * TODO: convert into a finite state machine + * + * @author abhinavsingh + * + */ +class JAXLSock5 { + + private $client = null; + + protected $transport = null; + protected $ip = null; + protected $port = null; + + public function __construct($transport='tcp') { + $this->transport = $transport; + $this->client = new JAXLSocketClient(); + $this->client->set_callback(array(&$this, 'on_response')); + } + + public function __destruct() { + + } + + public function connect($ip, $port=1080) { + $this->ip = $ip; + $this->port = $port; + $sock_path = $this->_sock_path(); + + if($this->client->connect($sock_path)) { + _debug("established connection to $sock_path"); + return true; + } + else { + _error("unable to connect $sock_path"); + return false; + } + } + + // + // Three phases of SOCK5 + // + + // Negotiation pkt consists of 3 part: + // 0x05 => Sock protocol version + // 0x01 => Number of method identifier octet + // + // Following auth methods are defined: + // 0x00 => No authentication required + // 0x01 => GSSAPI + // 0x02 => USERNAME/PASSWORD + // 0x03 to 0x7F => IANA ASSIGNED + // 0x80 to 0xFE => RESERVED FOR PRIVATE METHODS + // 0xFF => NO ACCEPTABLE METHODS + public function negotiate() { + $pkt = pack("C3", 0x05, 0x01, 0x00); + $this->client->send($pkt); + + // enter sub-negotiation state + } + + public function relay_request() { + // enter wait for reply state + } + + public function send_data() { + + } + + // + // Socket client callback + // + + public function on_response($raw) { + _debug($raw); + } + + // + // Private + // + + protected function _sock_path() { + return $this->transport.'://'.$this->ip.':'.$this->port; + } + +} + +?> Index: externals/JAXL/core/jaxl_socket_client.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_socket_client.php @@ -0,0 +1,219 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +require_once JAXL_CWD.'/core/jaxl_loop.php'; + +/** + * + * Enter description here ... + * @author abhinavsingh + * + */ +class JAXLSocketClient { + + private $host = null; + private $port = null; + private $transport = null; + private $stream_context = null; + private $blocking = false; + + public $fd = null; + + public $errno = null; + public $errstr = null; + private $timeout = 10; + + private $ibuffer = ""; + private $obuffer = ""; + private $compressed = false; + + private $recv_bytes = 0; + private $send_bytes = 0; + + private $recv_cb = null; + private $recv_chunk_size = 1024; + private $writing = false; + + public function __construct($stream_context=null) { + $this->stream_context = $stream_context; + } + + public function __destruct() { + //_debug("cleaning up xmpp socket..."); + $this->disconnect(); + } + + public function set_callback($recv_cb) { + $this->recv_cb = $recv_cb; + } + + /** + * @param string | resource $socket_path + */ + public function connect($socket_path) { + if(gettype($socket_path) == "string") { + $path_parts = explode(":", $socket_path); + $this->transport = $path_parts[0]; + $this->host = substr($path_parts[1], 2, strlen($path_parts[1])); + if(sizeof($path_parts) == 3) $this->port = $path_parts[2]; + + _info("trying ".$socket_path); + if($this->stream_context) $this->fd = @stream_socket_client($socket_path, $this->errno, $this->errstr, $this->timeout, STREAM_CLIENT_CONNECT, $this->stream_context); + else $this->fd = @stream_socket_client($socket_path, $this->errno, $this->errstr, $this->timeout); + } + else { + $this->fd = &$socket_path; + } + + if($this->fd) { + _debug("connected to ".$socket_path.""); + stream_set_blocking($this->fd, $this->blocking); + + // watch descriptor for read/write events + JAXLLoop::watch($this->fd, array( + 'read' => array(&$this, 'on_read_ready') + )); + + return true; + } + else { + _error("unable to connect ".$socket_path." with error no: ".$this->errno.", error str: ".$this->errstr.""); + $this->disconnect(); + return false; + } + } + + public function disconnect() { + JAXLLoop::unwatch($this->fd, array( + 'read' => true, + 'write' => true + )); + @fclose($this->fd); + $this->fd = null; + } + + public function compress() { + $this->compressed = true; + //stream_filter_append($this->fd, 'zlib.inflate', STREAM_FILTER_READ); + //stream_filter_append($this->fd, 'zlib.deflate', STREAM_FILTER_WRITE); + } + + public function crypt() { + // set blocking (since tls negotiation fails if stream is non-blocking) + stream_set_blocking($this->fd, true); + + $ret = stream_socket_enable_crypto($this->fd, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); + if($ret == false) { + $ret = stream_socket_enable_crypto($this->fd, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT); + if($ret == false) { + $ret = stream_socket_enable_crypto($this->fd, true, STREAM_CRYPTO_METHOD_SSLv2_CLIENT); + if($ret == false) { + $ret = stream_socket_enable_crypto($this->fd, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT); + } + } + } + + // switch back to non-blocking + stream_set_blocking($this->fd, false); + return $ret; + } + + public function send($data) { + $this->obuffer .= $data; + + // add watch for write events + if($this->writing) return; + JAXLLoop::watch($this->fd, array( + 'write' => array(&$this, 'on_write_ready') + )); + $this->writing = true; + } + + public function on_read_ready($fd) { + //_debug("on read ready called"); + $raw = @fread($fd, $this->recv_chunk_size); + $bytes = strlen($raw); + + if($bytes === 0) { + $meta = stream_get_meta_data($fd); + if($meta['eof'] === TRUE) { + _warning("socket eof, disconnecting"); + JAXLLoop::unwatch($fd, array( + 'read' => true + )); + $this->disconnect(); + return; + } + } + + $this->recv_bytes += $bytes; + $total = $this->ibuffer.$raw; + + $this->ibuffer = ""; + _debug("read ".$bytes."/".$this->recv_bytes." of data"); + if($bytes > 0) _debug($raw); + + // callback + if($this->recv_cb) call_user_func($this->recv_cb, $raw); + } + + public function on_write_ready($fd) { + //_debug("on write ready called"); + $total = strlen($this->obuffer); + $bytes = @fwrite($fd, $this->obuffer); + $this->send_bytes += $bytes; + + _debug("sent ".$bytes."/".$this->send_bytes." of data"); + _debug(substr($this->obuffer, 0, $bytes)); + + $this->obuffer = substr($this->obuffer, $bytes, $total-$bytes); + + // unwatch for write if obuffer is empty + if(strlen($this->obuffer) === 0) { + JAXLLoop::unwatch($fd, array( + 'write' => true + )); + $this->writing = false; + } + + //_debug("current obuffer size: ".strlen($this->obuffer).""); + } + +} + +?> Index: externals/JAXL/core/jaxl_socket_server.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_socket_server.php @@ -0,0 +1,258 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_loop.php'; + +class JAXLSocketServer { + + public $fd = null; + + private $clients = array(); + private $recv_chunk_size = 1024; + private $send_chunk_size = 8092; + private $accept_cb = null; + private $request_cb = null; + private $blocking = false; + private $backlog = 200; + + public function __construct($path, $accept_cb, $request_cb) { + $this->accept_cb = $accept_cb; + $this->request_cb = $request_cb; + + $ctx = stream_context_create(array('socket'=>array('backlog'=>$this->backlog))); + if(($this->fd = @stream_socket_server($path, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctx)) !== false) { + if(@stream_set_blocking($this->fd, $this->blocking)) { + JAXLLoop::watch($this->fd, array( + 'read' => array(&$this, 'on_server_accept_ready') + )); + _info("socket ready to accept on path ".$path); + } + else { + _error("unable to set non block flag"); + } + } + else { + _error("unable to establish socket server, errno: ".$errno.", errstr: ".$errstr); + } + } + + public function __destruct() { + _info("shutting down socket server"); + } + + public function read($client_id) { + //_debug("reactivating read on client sock"); + $this->add_read_cb($client_id); + } + + public function send($client_id, $data) { + $this->clients[$client_id]['obuffer'] .= $data; + $this->add_write_cb($client_id); + } + + public function close($client_id) { + $this->clients[$client_id]['close'] = true; + $this->add_write_cb($client_id); + } + + public function on_server_accept_ready($server) { + //_debug("got server accept"); + $client = @stream_socket_accept($server, 0, $addr); + if(!$client) { + _error("unable to accept new client conn"); + return; + } + + if(@stream_set_blocking($client, $this->blocking)) { + $client_id = (int) $client; + $this->clients[$client_id] = array( + 'fd' => $client, + 'ibuffer' => '', + 'obuffer' => '', + 'addr' => trim($addr), + 'close' => false, + 'closed' => false, + 'reading' => false, + 'writing' => false + ); + + _debug("accepted connection from client#".$client_id.", addr:".$addr); + + // if accept callback is registered + // callback and let user land take further control of what to do + if($this->accept_cb) { + call_user_func($this->accept_cb, $client_id, $this->clients[$client_id]['addr']); + } + // if no accept callback is registered + // close the accepted connection + else { + @fclose($client); + $this->clients[$client_id]['closed'] = true; + unset($this->clients[$client_id]); + } + } + else { + _error("unable to set non block flag"); + } + } + + public function on_client_read_ready($client) { + // deactive socket for read + $client_id = (int) $client; + //_debug("client#$client_id is read ready"); + $this->del_read_cb($client_id); + + $raw = fread($client, $this->recv_chunk_size); + $bytes = strlen($raw); + + _debug("recv $bytes bytes from client#$client_id"); + //_debug($raw); + + if($bytes === 0) { + $meta = stream_get_meta_data($client); + if($meta['eof'] === TRUE) { + _debug("socket eof client#".$client_id.", closing"); + $this->del_read_cb($client_id); + + @fclose($client); + unset($this->clients[$client_id]); + return; + } + } + + $total = $this->clients[$client_id]['ibuffer'] . $raw; + if($this->request_cb) + call_user_func($this->request_cb, $client_id, $total); + $this->clients[$client_id]['ibuffer'] = ''; + } + + public function on_client_write_ready($client) { + $client_id = (int) $client; + _debug("client#$client_id is write ready"); + + try { + // send in chunks + $total = $this->clients[$client_id]['obuffer']; + $written = @fwrite($client, substr($total, 0, $this->send_chunk_size)); + + if($written === false) { + // fwrite failed + _warning("====> fwrite failed"); + $this->clients[$client_id]['obuffer'] = $total; + } + else if($written == strlen($total) || $written == $this->send_chunk_size) { + // full chunk written + //_debug("full chunk written"); + $this->clients[$client_id]['obuffer'] = substr($total, $this->send_chunk_size); + } + else { + // partial chunk written + //_debug("partial chunk $written written"); + $this->clients[$client_id]['obuffer'] = substr($total, $written); + } + + // if no more stuff to write, remove write handler + if(strlen($this->clients[$client_id]['obuffer']) === 0) { + $this->del_write_cb($client_id); + + // if scheduled for close and not closed do it and clean up + if($this->clients[$client_id]['close'] && !$this->clients[$client_id]['closed']) { + @fclose($client); + $this->clients[$client_id]['closed'] = true; + unset($this->clients[$client_id]); + + _debug("closed client#".$client_id); + } + } + } + catch(JAXLException $e) { + _debug("====> got fwrite exception"); + } + } + + // + // client sock event register utils + // + + protected function add_read_cb($client_id) { + if($this->clients[$client_id]['reading']) + return; + + JAXLLoop::watch($this->clients[$client_id]['fd'], array( + 'read' => array(&$this, 'on_client_read_ready') + )); + + $this->clients[$client_id]['reading'] = true; + } + + protected function add_write_cb($client_id) { + if($this->clients[$client_id]['writing']) + return; + + JAXLLoop::watch($this->clients[$client_id]['fd'], array( + 'write' => array(&$this, 'on_client_write_ready') + )); + + $this->clients[$client_id]['writing'] = true; + } + + protected function del_read_cb($client_id) { + if(!$this->clients[$client_id]['reading']) + return; + + JAXLLoop::unwatch($this->clients[$client_id]['fd'], array( + 'read' => true + )); + + $this->clients[$client_id]['reading'] = false; + } + + protected function del_write_cb($client_id) { + if(!$this->clients[$client_id]['writing']) + return; + + JAXLLoop::unwatch($this->clients[$client_id]['fd'], array( + 'write' => true + )); + + $this->clients[$client_id]['writing'] = false; + } + +} + +?> Index: externals/JAXL/core/jaxl_util.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_util.php @@ -0,0 +1,67 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +/** + * + * @author abhinavsingh + * + */ +class JAXLUtil { + + public static function get_nonce($binary=true) { + $nce = ''; + mt_srand((double) microtime()*10000000); + for($i=0; $i<32; $i++) $nce .= chr(mt_rand(0, 255)); + return $binary ? $nce : base64_encode($nce); + } + + public static function get_dns_srv($domain) { + $rec = dns_get_record("_xmpp-client._tcp.".$domain, DNS_SRV); + if(is_array($rec)) { + if(sizeof($rec) == 0) return array($domain, 5222); + if(sizeof($rec) > 0) return array($rec[0]['target'], $rec[0]['port']); + } + } + + public static function pbkdf2($data, $secret, $iteration, $dkLen=32, $algo='sha1') { + return ''; + } + +} + +?> Index: externals/JAXL/core/jaxl_xml.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_xml.php @@ -0,0 +1,199 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +/** + * + * Details: http://abhinavsingh.com/blog/2012/09/jaxlxml-strophe-style-xml-builder-working-with-jaxl-a-networking-library-in-php-part-2/ + * Doc: http://jaxl.readthedocs.org/en/latest/users/xml_objects.html#jaxlxml + * + * @author abhinavsingh + * + */ +class JAXLXml { + + public $name; + public $ns = null; + public $attrs = array(); + public $text = null; + + public $childrens = array(); + public $parent = null; + public $rover = null; + + public function __construct() { + $argv = func_get_args(); + $argc = sizeof($argv); + + $this->name = $argv[0]; + + switch($argc) { + case 4: + $this->ns = $argv[1]; + $this->attrs = $argv[2]; + $this->text = $argv[3]; + break; + case 3: + if(is_array($argv[1])) { + $this->attrs = $argv[1]; + $this->text = $argv[2]; + } + else { + $this->ns = $argv[1]; + if(is_array($argv[2])) { + $this->attrs = $argv[2]; + } + else { + $this->text = $argv[2]; + } + } + break; + case 2: + if(is_array($argv[1])) { + $this->attrs = $argv[1]; + } + else { + $this->ns = $argv[1]; + } + break; + default: + break; + } + + $this->rover = &$this; + } + + public function __destruct() { + + } + + public function attrs($attrs) { + $this->rover->attrs = array_merge($this->rover->attrs, $attrs); + return $this; + } + + public function match_attrs($attrs) { + $matches = true; + foreach($attrs as $k=>$v) { + if($this->attrs[$k] !== $v) { + $matches = false; + break; + } + } + return $matches; + } + + public function t($text, $append=FALSE) { + if(!$append) { + $this->rover->text = $text; + } + else { + if($this->rover->text === null) + $this->rover->text = ''; + $this->rover->text .= $text; + } + return $this; + } + + public function c($name, $ns=null, $attrs=array(), $text=null) { + $node = new JAXLXml($name, $ns, $attrs, $text); + $node->parent = &$this->rover; + $this->rover->childrens[] = &$node; + $this->rover = &$node; + return $this; + } + + public function cnode($node) { + $node->parent = &$this->rover; + $this->rover->childrens[] = &$node; + $this->rover = &$node; + return $this; + } + + public function up() { + if($this->rover->parent) $this->rover = &$this->rover->parent; + return $this; + } + + public function top() { + $this->rover = &$this; + return $this; + } + + public function exists($name, $ns=null, $attrs=array()) { + foreach($this->childrens as $child) { + if($ns) { + if($child->name == $name && $child->ns == $ns && $child->match_attrs($attrs)) + return $child; + } + else if($child->name == $name && $child->match_attrs($attrs)) { + return $child; + } + } + return false; + } + + public function update($name, $ns=null, $attrs=array(), $text=null) { + foreach($this->childrens as $k=>$child) { + if($child->name == $name) { + $child->ns = $ns; + $child->attrs($attrs); + $child->text = $text; + $this->childrens[$k] = $child; + break; + } + } + } + + public function to_string($parent_ns=null) { + $xml = ''; + + $xml .= '<'.$this->name; + if($this->ns && $this->ns != $parent_ns) $xml .= ' xmlns="'.$this->ns.'"'; + foreach($this->attrs as $k=>$v) if(!is_null($v) && $v !== FALSE) $xml .= ' '.$k.'="'.htmlspecialchars($v).'"'; + $xml .= '>'; + + foreach($this->childrens as $child) $xml .= $child->to_string($this->ns); + + if($this->text) $xml .= htmlspecialchars($this->text); + $xml .= 'name.'>'; + return $xml; + } + +} + +?> Index: externals/JAXL/core/jaxl_xml_stream.php =================================================================== --- /dev/null +++ externals/JAXL/core/jaxl_xml_stream.php @@ -0,0 +1,191 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +/** + * + * Enter description here ... + * @author abhinavsingh + * + */ +class JAXLXmlStream { + + private $delimiter = '\\'; + private $ns; + private $parser; + private $stanza; + private $depth = -1; + + private $start_cb; + private $stanza_cb; + private $end_cb; + + public function __construct() { + $this->init_parser(); + } + + private function init_parser() { + $this->depth = -1; + $this->parser = xml_parser_create_ns("UTF-8", $this->delimiter); + + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); + + xml_set_character_data_handler($this->parser, array(&$this, "handle_character")); + xml_set_element_handler($this->parser, array(&$this, "handle_start_tag"), array(&$this, "handle_end_tag")); + } + + public function __destruct() { + //_debug("cleaning up xml parser..."); + @xml_parser_free($this->parser); + } + + public function reset_parser() { + $this->parse_final(null); + @xml_parser_free($this->parser); + $this->parser = null; + $this->init_parser(); + } + + public function set_callback($start_cb, $end_cb, $stanza_cb) { + $this->start_cb = $start_cb; + $this->end_cb = $end_cb; + $this->stanza_cb = $stanza_cb; + } + + public function parse($str) { + xml_parse($this->parser, $str, false); + } + + public function parse_final($str) { + xml_parse($this->parser, $str, true); + } + + protected function handle_start_tag($parser, $name, $attrs) { + $name = $this->explode($name); + //echo "start of tag ".$name[1]." with ns ".$name[0].PHP_EOL; + + // replace ns with prefix + foreach($attrs as $key=>$v) { + $k = $this->explode($key); + + // no ns specified + if($k[0] == null) { + $attrs[$k[1]] = $v; + } + // xml ns + else if($k[0] == NS_XML) { + unset($attrs[$key]); + $attrs['xml:'.$k[1]] = $v; + } + else { + _error("==================> unhandled ns prefix on attribute"); + // remove attribute else will cause error with bad stanza format + // report to developer if above error message is ever encountered + unset($attrs[$key]); + } + } + + if($this->depth <= 0) { + $this->depth = 0; + $this->ns = $name[1]; + + if($this->start_cb) { + $stanza = new JAXLXml($name[1], $name[0], $attrs); + call_user_func($this->start_cb, $stanza); + } + } + else { + if(!$this->stanza) { + $stanza = new JAXLXml($name[1], $name[0], $attrs); + $this->stanza = &$stanza; + } + else { + $this->stanza->c($name[1], $name[0], $attrs); + } + } + + ++$this->depth; + } + + protected function handle_end_tag($parser, $name) { + $name = explode($this->delimiter, $name); + $name = sizeof($name) == 1 ? array('', $name[0]) : $name; + + //echo "depth ".$this->depth.", $name[1] tag ended".PHP_EOL.PHP_EOL; + + if($this->depth == 1) { + if($this->end_cb) { + $stanza = new JAXLXml($name[1], $this->ns); + call_user_func($this->end_cb, $stanza); + } + } + else if($this->depth > 1) { + if($this->stanza) $this->stanza->up(); + + if($this->depth == 2) { + if($this->stanza_cb) { + call_user_func($this->stanza_cb, $this->stanza); + $this->stanza = null; + } + } + } + + --$this->depth; + } + + protected function handle_character($parser, $data) { + //echo "depth ".$this->depth.", character ".$data." for stanza ".$this->stanza->name.PHP_EOL; + if($this->stanza) { + $this->stanza->t(htmlentities($data, ENT_COMPAT, "UTF-8"), TRUE); + } + } + + private function implode($data) { + return implode($this->delimiter, $data); + } + + private function explode($data) { + $data = explode($this->delimiter, $data); + $data = sizeof($data) == 1 ? array(null, $data[0]) : $data; + return $data; + } + +} + +?> Index: externals/JAXL/docs/Makefile =================================================================== --- /dev/null +++ externals/JAXL/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Jaxl.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Jaxl.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Jaxl" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Jaxl" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." Index: externals/JAXL/docs/conf.py =================================================================== --- /dev/null +++ externals/JAXL/docs/conf.py @@ -0,0 +1,242 @@ +# -*- coding: utf-8 -*- +# +# Jaxl documentation build configuration file, created by +# sphinx-quickstart on Sun Jul 15 03:08:42 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.viewcode'] +# , 'sphinxcontrib.phpdomain' + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Jaxl' +copyright = u'2012, Abhinav Singh' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '3.0' +# The full version, including alpha/beta/rc tags. +release = '3.0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'pastie' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'nature' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Jaxldoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Jaxl.tex', u'Jaxl Documentation', + u'Abhinav Singh', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'jaxl', u'Jaxl Documentation', + [u'Abhinav Singh'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'Jaxl', u'Jaxl Documentation', + u'Abhinav Singh', 'Jaxl', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' Index: externals/JAXL/docs/developers/core_stack.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/developers/core_stack.rst @@ -0,0 +1,34 @@ +Core Stack +========== +That has a paragraph about a main subject and is set when the '=' +is at least the same length of the title itself. + +Main Event Loop +---------------- + +Finite State Machine +-------------------- + +TCP/IP Socket Client +-------------------- + +TCP/IP Socket Server +-------------------- + +Event Emitter +------------- + +Streaming XML Parser +-------------------- + +XML Objects +----------- + +Timed Job Dispatcher +-------------------- + +Inter-Process Communication (IPC) +--------------------------------- + +Remote Shell & Debug Console +----------------------------- \ No newline at end of file Index: externals/JAXL/docs/developers/http_stack.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/developers/http_stack.rst @@ -0,0 +1,14 @@ +HTTP Stack +========== + +Request Object +-------------- + +Bit by Bit Pushing +------------------ + +Multipart Form Data +------------------- + +Chunked Encoding +---------------- Index: externals/JAXL/docs/developers/introduction.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/developers/introduction.rst @@ -0,0 +1,10 @@ +.. _developer-introduction: + +Introduction +============ + +Design Philosophy +----------------- + +Contributing to the library +--------------------------- \ No newline at end of file Index: externals/JAXL/docs/developers/xmpp_stack.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/developers/xmpp_stack.rst @@ -0,0 +1,8 @@ +XMPP Stack +========== + +XMPP Streams +------------ + +XMPP Stanza +----------- \ No newline at end of file Index: externals/JAXL/docs/index.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/index.rst @@ -0,0 +1,51 @@ +Welcome to Jaxl's documentation! +================================ +Jaxl v3.x is a successor of v2.x (and is NOT backward compatible), +carrying a lot of code from v2.x while throwing away the ugly parts. +A lot of components have been re-written keeping in mind the feedback from +the developer community over the last 4 years. Also Jaxl now shares a few +philosophies from my experience with erlang and python languages. + +Jaxl is an asynchronous, non-blocking I/O, event based PHP library +for writing custom TCP/IP client and server implementations. +From it's previous versions, library inherits a full blown stable support +for XMPP protocol stack. In v3.0, support for HTTP protocol stack was +also added. + +At the heart of every protocol stack sits a Core stack. It contains all the +building blocks for everything that we aim to do with Jaxl library. Both +XMPP and HTTP protocol stacks are written on top of the Core stack. Infact +the source code of protocol implementations knows nothing about the +standard (inbuilt) PHP socket and stream methods. + +Users Guide +------------ + +.. toctree:: + :maxdepth: 2 + + users/getting_started + users/jaxl_instance + users/jaxlctl + users/logging + users/cron_jobs + +XMPP Users Guide: +----------------- + +.. toctree:: + :maxdepth: 2 + + users/xmpp_examples + users/xml_objects + users/xmpp_extensions + +HTTP Users Guide: +----------------- + +.. toctree:: + :maxdepth: 2 + + users/http_examples + users/http_extensions + \ No newline at end of file Index: externals/JAXL/docs/users/cron_jobs.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/cron_jobs.rst @@ -0,0 +1,61 @@ +Cron Jobs +========= +``JAXLClock`` maintains a global clock which is updated after every iteration of the :ref:`main select loop `. +During the clock tick phase, ``JAXLClock`` also dispatches any scheduled cron jobs. + +Lets try some cron job scheduling using Jaxl interactive shell: + + >>> ./jaxlctl shell + jaxl 1> + jaxl 1> function do_job($params) { + ....... echo "cron job called"; + ....... } + jaxl 2> + jaxl 2> $ref = JAXLLoop::$clock->call_fun_after( + ....... 4000, + ....... 'do_job', + ....... 'some_parameters' + ....... ); + jaxl 3> echo $ref; + 1 + jaxl 4> + cron job called + jaxl 5> quit + >>> + +We just saw a live example of a cron job. Using ``JAXLClock::call_fun_after/3`` we were able to +call our ``do_job`` function after 4000 microseconds. + +.. note:: + + Since cron jobs are called inside main select loop, do not execute long running cron jobs using + ``JAXLClock`` else the main select loop will not be able to detect any new activity on + watched file descriptors. In short, these cron job callbacks are blocking. + + In future, cron jobs might get executed in a seperate process space, overcoming the above limitation. + Until then know what your jobs are doing and for how long or execute them in a seperate process space + yourself. You have been warned !!! + +one time jobs +------------- +``call_fun_after($time, $callback, $args)`` + +schedules $callback with $args after $time microseconds + +periodic jobs +------------- +``call_fun_periodic($time, $callback, $args)`` + +schedules periodic $callback with $args after $time microseconds + +cancel a job +------------ +``cancel_fun_call($ref)`` + +cancels a previously scheduled $callback + +detecting bottlenecks +--------------------- +``tc($callback, $args)`` + +calculate execution time of a $callback with $args Index: externals/JAXL/docs/users/getting_started.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/getting_started.rst @@ -0,0 +1,161 @@ +Getting Started +=============== + +Requirements +------------ +No external component or library is required. +You simply need a standard PHP installation to work with Jaxl. + +Library has been developed and tested extensively on +linux operating systems. But there is no reason why it should +not work on other OS. File an `issue `_ if you face any glitches. + +Download & Install +------------------ +Download a stable tagged v3.x release from `https://github.com/abhinavsingh/JAXL/tags `_ + +You can also checkout git branch and switch to a tag of your choice: + + >>> git clone git://github.com/abhinavsingh/JAXL.git + >>> cd JAXL/ + >>> git tag -l + >>> git checkout some-tag-name + +To install Jaxl library globally, simply append path of the downloaded ``JAXL`` folder +to ``include_path`` directive inside your ``php.ini``. This will allow us to use Jaxl +library simply by doing: + +``require 'jaxl.php';`` + +Alternately, if you don't want to edit ``php.ini`` or in case you don't have +access to the ini file, simply use: + +``require '/full/path/to/JAXL/jaxl.php';`` + +to start using Jaxl library. + +Library Structure +----------------- +Jaxl library comprises of following packages: + + * ``jaxl-core`` + + contains generic networking and eventing components + + * ``jaxl-xmpp`` + + contains xmpp rfc implementation + + * ``jaxl-xmpp-xep`` + + contains various xmpp xep implementation + + * ``jaxl-http`` + + contains http rfc implementation + + * ``jaxl-docs`` + + this documentation comes from this package + + * ``jaxl-tests`` + + test suites for all the above packages + +Inside Jaxl everything that you will interact with will be an object which +will emit events and callbacks which we will be able to catch in our applications +for custom processing and routing. Listed below are a few main objects: + + #. Core Stack + + * ``JAXLLoop`` + + main select loop + + * ``JAXLClock`` + + timed job/callback dispatcher + + * ``JAXLEvent`` + + event registry and emitter + + * ``JAXLFsm`` + + generic finite state machine + + * ``JAXLSocketClient`` + + generic tcp/udp client + + * ``JAXLSocketServer`` + + generic tcp/udp server + + * ``JAXLXmlStream`` + + streaming XML parser + + * ``JAXLXml`` + + custom XML object implementation + + * ``JAXLLogger`` + + logging facility + + #. XMPP Stack + + * ``XMPPStream`` + + base xmpp rfc implementation + + * ``XMPPStanza`` + + provides easy access patterns over xmpp stanza (wraps ``JAXLXml``) + + * ``XMPPIq`` + + xmpp iq stanza object (extends ``XMPPStanza``) + + * ``XMPPMsg`` + + xmpp msg stanza object (extends ``XMPPStanza``) + + * ``XMPPPres`` + + xmpp pres stanza object (extends ``XMPPStanza``) + + * ``XMPPXep`` + + abstract xmpp extension (extended by XEP implementations) + + * ``XMPPJid`` + + xmpp jid object + + #. HTTP Stack + + * ``HTTPServer`` + + http server implementation + + * ``HTTPClient`` + + http client implementation + + * ``HTTPRequest`` + + http request object + + * ``HTTPResponse`` + + http response object + +Questions, Bugs and Issues +-------------------------- +If you have any questions kindly post them on `google groups `_. Groups are the quickest +way to get an answer to your questions which is actively monitored by core developers. + +If you are facing a bug or issue, please report that it on `github issue tracker `_. +You can even :ref:`contribute to the library ` if you already have fixed the bug. Index: externals/JAXL/docs/users/http_examples.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/http_examples.rst @@ -0,0 +1,102 @@ +HTTP Examples +============= + +Writing HTTP Server +------------------- +Intialize an ``HTTPServer`` instance + +.. code-block:: ruby + + require_once 'jaxl.php'; + require_once JAXL_CWD.'/http/http_server.php'; + $http = new HTTPServer(); + +By default ``HTTPServer`` will listen on port 9699. You can pass a port number as first parameter to change this. + +Define a callback method that will accept all incoming ``HTTPRequest`` objects + +.. code-block:: ruby + + function on_request($request) { + if($request->method == 'GET') { + $body = json_encode($request); + $request->ok($body, array('Content-Type'=>'application:json')); + } + else { + $request->not_found(); + } + } + +``on_request`` callback method will receive a ``HTTPRequest`` object instance. +For this example, we will simply echo back json encoded ``$request`` object for +every http GET request. + +Start http server: + +.. code-block:: ruby + + $http->start('on_request'); + +We pass ``on_request`` method as first parameter to ``HTTPServer::start/1``. +If nothing is passed, requests will fail with a default 404 not found error message + +Writing REST API Server +----------------------- +Intialize an ``HTTPServer`` instance + +.. code-block:: ruby + + require_once 'jaxl.php'; + require_once JAXL_CWD.'/http/http_server.php'; + $http = new HTTPServer(); + +By default ``HTTPServer`` will listen on port 9699. You can pass a port number as first parameter to change this. + +Define our REST resources callback methods: + +.. code-block:: ruby + + function index($request) { + $request->send_response( + 200, array('Content-Type'=>'text/html'), + '

Jaxl Http Server

upload a file' + ); + $request->close(); + } + + function upload($request) { + if($request->method == 'GET') { + $request->send_response( + 200, array('Content-Type'=>'text/html'), + '

Jaxl Http Server

' + ); + } + else if($request->method == 'POST') { + if($request->body === null && $request->expect) { + $request->recv_body(); + } + else { + // got upload body, save it + _debug("file upload complete, got ".strlen($request->body)." bytes of data"); + $request->close(); + } + } + } + +Next we need to register dispatch rules for our callbacks above: + +.. code-block:: ruby + + $index = array('index', '^/$'); + $upload = array('upload', '^/upload', array('GET', 'POST')); + $rules = array($index, $upload); + $http->dispatch($rules); + +Start REST api server: + +.. code-block:: ruby + + $http->start(); + +Make an HTTP request +-------------------- Index: externals/JAXL/docs/users/http_extensions.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/http_extensions.rst @@ -0,0 +1,49 @@ +HTTP Extensions +=============== + +Dispatch Rules +-------------- +Dispatch rules are convinient way of redirecting callback for a specific request pattern to a custom +methods inside your application. A dispatch rule consists of following 4 match information: + + * ``$callback`` + + reference to a method that will be callback'd when a matching request is received + + * ``$pattern`` + + a regular expression for matching on url path + + * ``$methods`` + + (optional) if not specified rule will match for all HTTP Methods. + if specified, must be an array of HTTP Method in uppercase. + + * ``$extra`` + + (reserved) this is for future where we will allow matching on + headers, session, cookies etc. + +Below are a few examples of dispatch rules: + +.. code-block:: ruby + + $index = array('serve_index_page', '^/'); + $upload_form = array('serve_upload_form', '^/upload', array('GET')); + $upload_handler = array('handle_upload_form', '^/upload', array('POST')); + +Some REST CRUD dispatch rules: + +.. code-block:: ruby + + $event_create = array('create_event', '^/event/create/$', array('PUT')); + $event_read = array('read_event', '^/event/(?P\d+)/$', array('GET', 'HEAD')); + $event_update = array('update_event', '^/event/(?P\d+)/$', array('POST')); + $event_delete = array('delete_event', '^/event/(?P\d+)/$', array('DELETE')); + +Finally don't forget to active these dispatch rules by doing: + +.. code-block:: ruby + + $rules = array($index, $upload_form, $upload_handler, $event_create, $event_read, $event_update, $event_delete); + $http->dispatch($rules); Index: externals/JAXL/docs/users/jaxl_instance.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/jaxl_instance.rst @@ -0,0 +1,166 @@ +.. _jaxl-instance: + +JAXL Instance +============= +``JAXL`` instance configure/manage other :ref:`sub-packages `. +It provides an event based callback methodology on various underlying object. Whenever required +``JAXL`` instance will itself perform the configured defaults. + +Constructor options +------------------- + + #. ``jid`` + #. ``pass`` + #. ``resource`` + + If not passed Jaxl will use a random resource value + + #. ``auth_type`` + + DIGEST-MD5, PLAIN (default), CRAM-MD5, ANONYMOUS, X-FACEBOOK-PLATFORM + + #. ``host`` + #. ``port`` + #. ``bosh_url`` + #. ``log_path`` + #. ``log_level`` + + ``JAXL_ERROR``, ``JAXL_WARNING``, ``JAXL_NOTICE``, ``JAXL_INFO`` (default), ``JAXL_DEBUG`` + + #. ``fb_access_token`` + + required when using X-FACEBOOK-PLATFORM auth mechanism + + #. ``fb_app_key`` + + required when using X-FACEBOOK-PLATFORM auth mechanism + + #. ``force_tls`` + #. ``stream_context`` + #. ``priv_dir`` + + Jaxl creates 4 directories names ``log``, ``tmp``, ``run`` and ``sock`` inside a private directory + which defaults to ``JAXL_CWD.'/.jaxl'``. If this option is passed, it will overwrite default private + directory. + + .. note:: + + Jaxl currently doesn't check upon the permissions of passed ``priv_dir``. Make sure Jaxl library + have sufficient permissions to create above mentioned directories. + +Available Event Callbacks +------------------------- + +Following ``$ev`` are available on ``JAXL`` lifecycle for registering callbacks: + + #. ``on_connect`` + + ``JAXL`` instance has connected successfully + + #. ``on_connect_error`` + + ``JAXL`` instance failed to connect + + #. ``on_stream_start`` + + ``JAXL`` instance has successfully initiated XMPP stream with the jabber server + + #. ``on_stream_features`` + + ``JAXL`` instance has received supported stream features + + #. ``on_auth_success`` + + authentication successful + + #. ``on_auth_failure`` + + authentication failed + + #. ``on_presence_stanza`` + + ``JAXL`` instance has received a presence stanza + + #. ``on_{$type}_message`` + + ``JAXL`` instance has received a message stanza. ``$type`` can be ``chat``, ``groupchat``, ``headline``, ``normal``, ``error`` + + #. ``on_stanza_id_{$id}`` + + Useful when dealing with iq stanza. This event is fired when ``JAXL`` instance has received response to a particular + xmpp stanza id + + #. ``on_{$name}_stanza`` + + Useful when dealing with custom xmpp stanza + + #. ``on_disconnect`` + + ``JAXL`` instance has disconnected from the jabber server + +Available Methods +----------------- + +Following methods are available on initialized ``JAXL`` instance object: + + #. ``get_pid_file_path()`` + + returns path of ``JAXL`` instance pid file + + #. ``get_sock_file_path()`` + + returns path to ``JAXL`` ipc unix socket domain + + #. ``require_xep($xeps=array())`` + + autoload and initialize passed XEP's + + #. ``add_cb($ev, $cb, $pri=1)`` + + add a callback to function ``$cb`` on event ``$ev``, returns a reference of added callback + + #. ``del_cb($ref)`` + + delete previously registered event callback + + #. ``set_status($status, $show, $priority)`` + + send a presence status stanza + + #. ``send_chat_msg($to, $body, $thread=null, $subject=null)`` + + send a message stanza of type chat + + #. ``get_vcard($jid=null, $cb=null)`` + + fetch vcard for bare ``$jid``, passed ``$cb`` will be called with received vcard stanza + + #. ``get_roster($cb=null)`` + + fetch roster list of connected jabber client, passed ``$cb`` will be called with received roster stanza + + #. ``start($opts=array())`` + + start configured ``JAXL`` instance, optionally accepts two options specified below: + + #. ``--with-debug-shell`` + + start ``JAXL`` instance and enter an interactive console + + #. ``--with-unix-sock`` + + start ``JAXL`` instance with support for IPC and remote debugging + + #. ``send($stanza)`` + + send an instance of JAXLXml packet over connected socket + + #. ``send_raw($data)`` + + send raw payload over connected socket + + #. ``get_msg_pkt($attrs, $body=null, $thread=null, $subject=null, $payload=null)`` + + #. ``get_pres_pkt($attrs, $status=null, $show=null, $priority=null, $payload=null)`` + + #. ``get_iq_pkt($attrs, $payload)`` \ No newline at end of file Index: externals/JAXL/docs/users/jaxlctl.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/jaxlctl.rst @@ -0,0 +1,50 @@ +./jaxlctl +========= +Usage: ``./jaxlctl command [options...]`` + +``jaxlctl`` is a control script that can be seen as a useful tool for: + + * debugging daemons running in the background + * customize daemons on the fly + * monitoring daemons + * as a playground for learning XMPP/HTTP and Jaxl library itself + +Type ``./jaxlctl help`` to see list of available commands. + +.. note:: + + Various commands are still experimental. Know what you are doing before + using them in production. You have been warned !!! + +Interactive Shell +------------------ + + >>> ./jaxlctl shell + jaxl 1> + jaxl 1> // create a test message object + jaxl 1> $msg = new XMPPMsg(array('to'=>'friend@gmail.com'), 'Hello World!'); + jaxl 2> + jaxl 2> // object to string conversion + jaxl 2> print_r($msg->to_string()); + Hello World! + jaxl 3> + +Debug Running Instances +------------------------ + + >>> ./jaxlctl attach XXXXX + jaxl 1> + jaxl 1> // create a message to be sent + jaxl 1> $msg = new XMPPMsg(array('to'=>'friend@gmail.com'), 'Hello World!'); + jaxl 2> + jaxl 2> // this client is from the echo bot example + jaxl 2> global $client; + jaxl 3> + jaxl 3> // send the message packet + jaxl 3> $client->send($msg); + jaxl 4> + jaxl 4> // or we can directly do + jaxl 4> $client->send_chat_msg('friend@gmail.com', 'Hello World!'); + jaxl 5> + +Where ``XXXXX`` is the pid of running ``JAXL`` instance. Index: externals/JAXL/docs/users/logging.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/logging.rst @@ -0,0 +1,29 @@ +Logging Interface +================= +``JAXLLogger`` provides all the logging facilities that we will ever require. +When logging to ``STDOUT`` it also colorizes the log message depending upon its severity level. +When logging to a file it can also do periodic log rotation. + +log levels +---------- + + * JAXL_ERROR (red) + * JAXL_WARNING (blue) + * JAXL_NOTICE (yellow) + * JAXL_INFO (green) + * JAXL_DEBUG (white) + +global logging methods +---------------------- +Following global methods for logging are available: + + * ``_error($msg)`` + * ``_warning($msg)`` + * ``_notice($msg)`` + * ``_info($msg)`` + * ``_debug($msg)`` + +_colorize/2 +----------- +All the above global logging methods internally use ``_colorize($msg, $verbosity)`` to output colored +log message on the terminal. \ No newline at end of file Index: externals/JAXL/docs/users/xml_objects.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/xml_objects.rst @@ -0,0 +1,121 @@ +.. _xml-objects: + +Xml Objects +=========== +Jaxl library works with custom XML implementation which is similar to +inbuild PHP XML functions but is lightweight and easy to work with. + +JAXLXml +------- +``JAXLXml`` is the base XML object. Open up :ref:`Jaxl interactive shell ` and try some xml object creation/manipulation: + + >>> ./jaxlctl shell + jaxl 1> + jaxl 1> $xml = new JAXLXml( + ....... 'dummy', + ....... 'dummy:packet', + ....... array('attr1'=>'friend@gmail.com', 'attr2'=>''), + ....... 'Hello World!' + ....... ); + jaxl 2> echo $xml->to_string(); + Hello World! + jaxl 3> + +``JAXLXml`` constructor instance accepts following parameters: + + * ``JAXLXml($name, $ns, $attrs, $text)`` + * ``JAXLXml($name, $ns, $attrs)`` + * ``JAXLXml($name, $ns, $text)`` + * ``JAXLXml($name, $attrs, $text)`` + * ``JAXLXml($name, $attrs)`` + * ``JAXLXml($name, $ns)`` + * ``JAXLXml($name)`` + +``JAXLXml`` draws inspiration from StropheJS XML Builder class. Below are available methods +for modifying and manipulating an ``JAXLXml`` object: + + * ``t($text, $append=FALSE)`` + + update text of current rover + + * ``c($name, $ns=null, $attrs=array(), $text=null)`` + + append a child node at current rover + + * ``cnode($node)`` + + append a JAXLXml child node at current rover + + * ``up()`` + + move rover to one step up the xml tree + + * ``top()`` + + move rover back to top element in the xml tree + + * ``exists($name, $ns=null, $attrs=array())`` + + checks if a child with $name exists, return child ``JAXLXml`` if found otherwise false. This function returns at first matching child. + + * ``update($name, $ns=null, $attrs=array(), $text=null)`` + + update specified child element + + * ``attrs($attrs)`` + + merge new attrs with attributes of current rover + + * ``match_attrs($attrs)`` + + pass a kv pair of ``$attrs``, return bool if all passed keys matches their respective values in the xml packet + + * ``to_string()`` + + get string representation of the object + +``JAXLXml`` maintains a rover which points to the current level down the XML tree where +manipulation is performed. + +XMPPStanza +---------- +In the world of XMPP where everything incoming and outgoing payload is an ``JAXLXml`` instance code can become nasty, +developers can get lost in dirty XML manipulations spreaded all over the application code base and what not. +XML structures are not only unreadable for humans but even for machine. + +While an instance of ``JAXLXml`` provide direct access to XML ``name``, ``ns`` and ``text``, it can become painful and +time consuming when trying to retrieve or modify a particular ``attrs`` or ``childrens``. I was fed up of doing +``getAttributeByName``, ``setAttributeByName``, ``getChild`` etc everytime i had to access common XMPP Stanza attributes. + +``XMPPStanza`` is a wrapper on top of ``JAXLXml`` objects. Preserving all the functionalities of base ``JAXLXml`` +instance it also provide direct access to most common XMPP Stanza attributes like ``to``, ``from``, ``id``, ``type`` etc. +It also provides a framework for adding custom access patterns. + +``XMPPMsg``, ``XMPPPres`` and ``XMPPIq`` extends ``XMPPStanza`` and also add a few custom access patterns like +``body``, ``thread``, ``subject``, ``status``, ``show`` etc. + +Here is a list of default access patterns: + + #. ``name`` + #. ``ns`` + #. ``text`` + #. ``attrs`` + #. ``childrens`` + #. ``to`` + #. ``from`` + #. ``id`` + #. ``type`` + #. ``to_node`` + #. ``to_domain`` + #. ``to_resource`` + #. ``from_node`` + #. ``from_domain`` + #. ``from_resource`` + #. ``status`` + #. ``show`` + #. ``priority`` + #. ``body`` + #. ``thread`` + #. ``subject`` + + Index: externals/JAXL/docs/users/xmpp_examples.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/xmpp_examples.rst @@ -0,0 +1,120 @@ +XMPP Examples +============= + +Echo Bot Client +--------------- +include ``jaxl.php`` and initialize a new ``JAXL`` instance: + +.. code-block:: ruby + + require 'jaxl.php'; + $client = new JAXL(array( + 'jid' => 'user@domain.tld', + 'pass' => 'password' + )); + +We just initialized a new ``JAXL`` instance by passing our jabber client ``jid`` and ``pass``. + +View list of :ref:`available options ` that can be passed to ``JAXL`` constructor. + +Next we need to register callbacks on events of interest using ``JAXL::add_cb/2`` method as shown below: + +.. code-block:: ruby + + $client->add_cb('on_auth_success', function() { + global $client; + $client->set_status("available!"); // set your status + $client->get_vcard(); // fetch your vcard + $client->get_roster(); // fetch your roster list + }); + + $client->add_cb('on_chat_message', function($msg) { + global $client; + + // echo back + $msg->to = $msg->from; + $msg->from = $client->full_jid->to_string(); + $client->send($msg); + }); + + $client->add_cb('on_disconnect', function() { + _debug("got on_disconnect cb"); + }); + +We just registered callbacks on ``on_auth_success``, ``on_chat_message`` and ``on_disconnect`` events +that will occur inside our configured ``JAXL`` instance lifecycle. +We also passed a method that will be called (with parameters if any) when the event has been detected. + +See list of :ref:`available event callbacks ` that we can hook to inside ``JAXL`` instance lifecycle. + +Received ``$msg`` parameter with ``on_chat_message`` event callback above, will be an instance of ``XMPPMsg`` which +extends ``XMPPStanza`` class, that allows us easy to use access patterns to common XMPP stanza attributes like +``to``, ``from``, ``type``, ``id`` to name a few. + +We were also able to access our xmpp client full jabber id by calling ``$client->full_jid``. This attribute of +``JAXL`` instance is available from ``on_auth_success`` event. ``full_jid`` attribute is an instance of ``XMPPJid``. + +To send our echo back ``$msg`` packet we called ``JAXL::send/1`` which accepts a single parameter which MUST be +an instance of ``JAXLXml``. Since ``XMPPStanza`` is a wrapper upon ``JAXLXml`` we can very well pass our modified +``$msg`` object to the send method. + +Read more about various :ref:`XML Objects ` and how they make writing XMPP applications fun and easy. +You can also :ref:`add custom access patterns ` upon received ``XMPPStanza`` objects. Since all access +patterns are evaluated upon first access and cached for later usage, adding hundreds of custom access patterns that +retrieves information from 100th child of received XML packet will not be an issue. + +We will finally start our xmpp client by calling: + +.. code-block:: ruby + + $client->start(); + +See list of :ref:`available options ` that can be passed to the ``JAXL::start/2`` method. +These options are particularly useful for debugging and monitoring. + +Echo Bot BOSH Client +-------------------- +Everything goes same for a cli BOSH client. To run above echo bot client example as a bosh client simply +pass additional parameters to ``JAXL`` constructor: + +.. code-block:: ruby + + require 'jaxl.php'; + $client = new JAXL(array( + 'jid' => 'user@domain.tld', + 'pass' => 'password', + 'bosh_url' => 'http://localhost:5280/http-bind' + )); + +You can even pass custom values for ``hold``, ``wait`` and other attributes. + +View list of :ref:`available options ` that can be passed to ``JAXL`` constructor. + +Echo Bot External Component +--------------------------- +Again almost everything goes same for an external component except a few custom ``JAXL`` constructor +parameter as shown below: + +.. code-block:: ruby + + require_once 'jaxl.php'; + $comp = new JAXL(array( + // (required) component host and secret + 'jid' => $argv[1], + 'pass' => $argv[2], + + // (required) destination socket + 'host' => $argv[3], + 'port' => $argv[4] + )); + +We will also need to include ``XEP0114`` which implements Jabber Component XMPP Extension. + +.. code-block:: ruby + + // (required) + $comp->require_xep(array( + '0114' // jabber component protocol + )); + +``JAXL::require_xep/1`` accepts an array of XEP numbers passed as strings. Index: externals/JAXL/docs/users/xmpp_extensions.rst =================================================================== --- /dev/null +++ externals/JAXL/docs/users/xmpp_extensions.rst @@ -0,0 +1,32 @@ +XMPP Extensions (XEP) +===================== + +Writing Custom XMPP Extension +----------------------------- + +Entity Discovery +---------------- + +Multi-User Chat +--------------- + +Direct MUC Invitation +--------------------- + +Publish-Subscribe +----------------- + +In-Band User Registration +------------------------- + +External Jabber Component +------------------------- + +Entity Capabilities +------------------- + +Delayed Delivery +---------------- + +XMPP Over HTTP (Bosh) +--------------------- Index: externals/JAXL/examples/curl.php =================================================================== --- /dev/null +++ externals/JAXL/examples/curl.php @@ -0,0 +1,51 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 2) { + echo "Usage: $argv[0] url\n"; + exit; +} + +require_once 'jaxl.php'; +JAXLLogger::$level = JAXL_DEBUG; +require_once JAXL_CWD.'/http/http_client.php'; + +$request = new HTTPClient($argv[1]); +$request->start(); + +?> Index: externals/JAXL/examples/echo_bosh_bot.php =================================================================== --- /dev/null +++ externals/JAXL/examples/echo_bosh_bot.php @@ -0,0 +1,108 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 3) { + echo "Usage: $argv[0] jid pass\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + // (required) credentials + 'jid' => $argv[1], + 'pass' => $argv[2], + + // (required) + 'bosh_url' => 'http://localhost:5280/http-bind', + + // (optional) srv lookup is done if not provided + // for bosh client 'host' value is used for 'route' attribute + //'host' => 'xmpp.domain.tld', + + // (optional) result from srv lookup used by default + // for bosh client 'port' value is used for 'route' attribute + //'port' => 5222, + + // (optional) + //'resource' => 'resource', + + // (optional) defaults to PLAIN if supported, else other methods will be automatically tried + 'auth_type' => @$argv[3] ? $argv[3] : 'PLAIN', + + 'log_level' => JAXL_INFO +)); + +// +// add necessary event callbacks here +// + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + $client->set_status("available!", "dnd", 10); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + $client->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$client->add_cb('on_chat_message', function($stanza) { + global $client; + + // echo back incoming message stanza + $stanza->to = $stanza->from; + $stanza->from = $client->full_jid->to_string(); + $client->send($stanza); +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/echo_bot.php =================================================================== --- /dev/null +++ externals/JAXL/examples/echo_bot.php @@ -0,0 +1,149 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// Run as: +// php examples/echo_bot.php root@localhost password +// php examples/echo_bot.php root@localhost password DIGEST-MD5 +// php examples/echo_bot.php localhost "" ANONYMOUS +if($argc < 3) { + echo "Usage: $argv[0] jid pass auth_type\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + // (required) credentials + 'jid' => $argv[1], + 'pass' => $argv[2], + + // (optional) srv lookup is done if not provided + //'host' => 'xmpp.domain.tld', + + // (optional) result from srv lookup used by default + //'port' => 5222, + + // (optional) defaults to false + //'force_tls' => true, + + // (optional) + //'resource' => 'resource', + + // (optional) defaults to PLAIN if supported, else other methods will be automatically tried + 'auth_type' => @$argv[3] ? $argv[3] : 'PLAIN', + + 'log_level' => JAXL_INFO +)); + +// +// required XEP's +// +$client->require_xep(array( + '0199' // XMPP Ping +)); + +// +// add necessary event callbacks here +// + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + + // fetch roster list + $client->get_roster(); + + // fetch vcard + $client->get_vcard(); + + // set status + $client->set_status("available!", "dnd", 10); +}); + +// by default JAXL instance catches incoming roster list results and updates +// roster list is parsed/cached and an event 'on_roster_update' is emitted +$client->add_cb('on_roster_update', function() { + //global $client; + //print_r($client->roster); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + _info("got on_auth_failure cb with reason $reason"); + $client->send_end_stream(); +}); + +$client->add_cb('on_chat_message', function($stanza) { + global $client; + + // echo back incoming chat message stanza + $stanza->to = $stanza->from; + $stanza->from = $client->full_jid->to_string(); + $client->send($stanza); +}); + +$client->add_cb('on_presence_stanza', function($stanza) { + global $client; + + $type = ($stanza->type ? $stanza->type : "available"); + $show = ($stanza->show ? $stanza->show : "???"); + _info($stanza->from." is now ".$type." ($show)"); + + if($type == "available") { + // fetch vcard + $client->get_vcard($stanza->from); + } +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// + +$client->start(array( + '--with-debug-shell' => true, + '--with-unix-sock' => true +)); +echo "done\n"; + +?> Index: externals/JAXL/examples/echo_component_bot.php =================================================================== --- /dev/null +++ externals/JAXL/examples/echo_component_bot.php @@ -0,0 +1,100 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc != 5) { + echo "Usage: $argv[0] jid pass host port\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$comp = new JAXL(array( + // (required) component host and secret + 'jid' => $argv[1], + 'pass' => $argv[2], + + // (required) + 'host' => @$argv[3], + 'port' => $argv[4], + + 'log_level' => JAXL_INFO +)); + +// +// XEP's required (required) +// +$comp->require_xep(array( + '0114' // jabber component protocol +)); + +// +// add necessary event callbacks here +// + +$comp->add_cb('on_auth_success', function() { + _info("got on_auth_success cb"); +}); + +$comp->add_cb('on_auth_failure', function($reason) { + global $comp; + $comp->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$comp->add_cb('on_chat_message', function($stanza) { + global $comp; + + // echo back incoming message stanza + $stanza->to = $stanza->from; + $stanza->from = $comp->jid->to_string(); + $comp->send($stanza); +}); + +$comp->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$comp->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/echo_http_server.php =================================================================== --- /dev/null +++ externals/JAXL/examples/echo_http_server.php @@ -0,0 +1,60 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// include and configure logger +require_once 'jaxl.php'; +JAXLLogger::$level = JAXL_INFO; + +// print usage notice and parse addr/port parameters if passed +_colorize("Usage: $argv[0] port (default: 9699)", JAXL_NOTICE); +$port = ($argc == 2 ? $argv[1] : 9699); + +// initialize http server +require_once JAXL_CWD.'/http/http_server.php'; +$http = new HTTPServer($port); + +// catch all incoming requests here +function on_request($request) { + $body = json_encode($request); + $request->ok($body, array('Content-Type'=>'application/json')); +} + +// start http server +$http->start('on_request'); + +?> Index: externals/JAXL/examples/echo_unix_sock_server.php =================================================================== --- /dev/null +++ externals/JAXL/examples/echo_unix_sock_server.php @@ -0,0 +1,61 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 2) { + echo "Usage: $argv[0] /path/to/server.sock\n"; + exit; +} + +require_once 'jaxl.php'; +JAXLLogger::$level = JAXL_INFO; + +$server = null; + +function on_request($client, $raw) { + global $server; + $server->send($client, $raw); + _info("got client callback ".$raw); +} + +@unlink($argv[1]); +$server = new JAXLSocketServer('unix://'.$argv[1], NULL, 'on_request'); + +JAXLLoop::run(); +echo "done\n"; + +?> Index: externals/JAXL/examples/http_bind.php =================================================================== --- /dev/null +++ externals/JAXL/examples/http_bind.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if(!isset($_GET['jid']) || !isset($_GET['pass'])) { + echo "invalid input"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once '../jaxl.php'; +$client = new JAXL(array( + 'jid' => $_GET['jid'], + 'pass' => $_GET['pass'], + 'bosh_url' => 'http://localhost:5280/http-bind', + 'log_level' => JAXL_DEBUG +)); + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/http_pre_bind.php =================================================================== --- /dev/null +++ externals/JAXL/examples/http_pre_bind.php @@ -0,0 +1,91 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// http pre bind php script +$body = file_get_contents("php://input"); +$body = new SimpleXMLElement($body); +$attrs = $body->attributes(); + +if(!@$attrs['to'] && !@$attrs['rid'] && !@$attrs['wait'] && !@$attrs['hold']) { + echo "invalid input"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once '../jaxl.php'; + +$to = (string)$attrs['to']; +$rid = (int)$attrs['rid']; +$wait = (int)$attrs['wait']; +$hold = (int)$attrs['hold']; +list($host, $port) = JAXLUtil::get_dns_srv($to); + +$client = new JAXL(array( + 'domain' => $to, + 'host' => $host, + 'port' => $port, + 'bosh_url' => 'http://localhost:5280/http-bind', + 'bosh_rid' => $rid, + 'bosh_wait' => $wait, + 'bosh_hold' => $hold, + 'auth_type' => 'ANONYMOUS', + 'log_level' => JAXL_INFO +)); + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + echo ''; + exit; +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + _info("got on_auth_failure cb with reason $reason"); + $client->send_end_stream(); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/http_rest_server.php =================================================================== --- /dev/null +++ externals/JAXL/examples/http_rest_server.php @@ -0,0 +1,117 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// include and configure logger +require_once 'jaxl.php'; +JAXLLogger::$level = JAXL_INFO; + +// print usage notice and parse addr/port parameters if passed +_colorize("Usage: $argv[0] port (default: 9699)", JAXL_NOTICE); +$port = ($argc == 2 ? $argv[1] : 9699); + +// initialize http server +require_once JAXL_CWD.'/http/http_server.php'; +$http = new HTTPServer($port); + +// callback method for dispatch rule (see below) +function index($request) { + $request->send_response( + 200, array('Content-Type'=>'text/html'), + '

Jaxl Http Server

upload a file' + ); + $request->close(); +} + +// callback method for dispatch rule (see below) +function upload($request) { + if($request->method == 'GET') { + $request->ok(array( + 'Content-Type'=>'text/html'), + '

Jaxl Http Server

' + ); + } + else if($request->method == 'POST') { + if($request->body === null && $request->expect) { + $request->recv_body(); + } + else { + // got upload body, save it + _info("file upload complete, got ".strlen($request->body)." bytes of data"); + $upload_data = $request->multipart->form_data[0]['body']; + $request->ok($upload_data, array('Content-Type'=>$request->multipart->form_data[0]['headers']['Content-Type'])); + } + } +} + +// add dispatch rules with callback method as first argument +$index = array('index', '^/$'); +$upload = array('upload', '^/upload', array('GET', 'POST')); + +// some REST CRUD style callback methods +// Refer: http://jaxl.readthedocs.org/en/latest/users/http_extensions.html#dispatch-rules +function create_event($request) { + _info("got event create request"); + $request->close(); +} + +function read_event($request, $pk) { + _info("got event read request for $pk"); + $request->close(); +} + +function update_event($request, $pk) { + _info("got event update request for $pk"); + $request->close(); +} + +function delete_event($request, $pk) { + _info("got event delete request for $pk"); + $request->close(); +} + +$event_create = array('create_event', '^/event/create/$', array('PUT')); +$event_read = array('read_event', '^/event/(?P\d+)/$', array('GET', 'HEAD')); +$event_update = array('update_event', '^/event/(?P\d+)/$', array('POST')); +$event_delete = array('delete_event', '^/event/(?P\d+)/$', array('DELETE')); + +// prepare rule set +$rules = array($index, $upload, $event_create, $event_read, $event_update, $event_delete); +$http->dispatch($rules); + +// start http server +$http->start(); Index: externals/JAXL/examples/muc_log_bot.php =================================================================== --- /dev/null +++ externals/JAXL/examples/muc_log_bot.php @@ -0,0 +1,146 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 5) { + echo "Usage: $argv[0] host jid pass room@service.domain.tld nickname\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + // (required) credentials + 'jid' => $argv[2], + 'pass' => $argv[3], + 'host' => $argv[1], + 'log_level' => JAXL_INFO +)); + +$client->require_xep(array( + '0045', // MUC + '0203', // Delayed Delivery + '0199' // XMPP Ping +)); + +// +// add necessary event callbacks here +// + +$_room_full_jid = $argv[4]."/".$argv[5]; +$room_full_jid = new XMPPJid($_room_full_jid); + +$client->add_cb('on_auth_success', function() { + global $client, $room_full_jid; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + + // join muc room + $client->xeps['0045']->join_room($room_full_jid); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + $client->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$client->add_cb('on_groupchat_message', function($stanza) { + global $client; + + $from = new XMPPJid($stanza->from); + $delay = $stanza->exists('delay', NS_DELAYED_DELIVERY); + + if($from->resource) { + echo "message stanza rcvd from ".$from->resource." saying... ".$stanza->body.($delay ? ", delay timestamp ".$delay->attrs['stamp'] : ", timestamp ".gmdate("Y-m-dTH:i:sZ")).PHP_EOL; + } + else { + $subject = $stanza->exists('subject'); + if($subject) { + echo "room subject: ".$subject->text.($delay ? ", delay timestamp ".$delay->attrs['stamp'] : ", timestamp ".gmdate("Y-m-dTH:i:sZ")).PHP_EOL; + } + } +}); + +$client->add_cb('on_presence_stanza', function($stanza) { + global $client, $room_full_jid; + + $from = new XMPPJid($stanza->from); + + // self-stanza received, we now have complete room roster + if(strtolower($from->to_string()) == strtolower($room_full_jid->to_string())) { + if(($x = $stanza->exists('x', NS_MUC.'#user')) !== false) { + if(($status = $x->exists('status', null, array('code'=>'110'))) !== false) { + $item = $x->exists('item'); + _info("xmlns #user exists with x ".$x->ns." status ".$status->attrs['code'].", affiliation:".$item->attrs['affiliation'].", role:".$item->attrs['role']); + } + else { + _info("xmlns #user have no x child element"); + } + } + else { + _warning("=======> odd case 1"); + } + } + // stanza from other users received + else if(strtolower($from->bare) == strtolower($room_full_jid->bare)) { + if(($x = $stanza->exists('x', NS_MUC.'#user')) !== false) { + $item = $x->exists('item'); + echo "presence stanza of type ".($stanza->type ? $stanza->type : "available")." received from ".$from->resource.", affiliation:".$item->attrs['affiliation'].", role:".$item->attrs['role'].PHP_EOL; + } + else { + _warning("=======> odd case 2"); + } + } + else { + _warning("=======> odd case 3"); + } + +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/multi_client.php =================================================================== --- /dev/null +++ externals/JAXL/examples/multi_client.php @@ -0,0 +1,129 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// enable multi client support +// this will force 1st parameter of callbacks +// as connected client instance +define('JAXL_MULTI_CLIENT', true); + +// input multiple account credentials +$accounts = array(); +$add_new = TRUE; +while($add_new) { + $jid = readline('Enter Jabber Id: '); + $pass = readline('Enter Password: '); + $accounts[] = array($jid, $pass); + $next = readline('Add another account (y/n): '); + $add_new = $next == 'y' ? TRUE : FALSE; +} + +// setup jaxl +require_once 'jaxl.php'; + +// +// common callbacks +// + +function on_auth_success($client) { + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + + // fetch roster list + $client->get_roster(); + + // fetch vcard + $client->get_vcard(); + + // set status + $client->set_status("available!", "dnd", 10); +} + +function on_auth_failure($client, $reason) { + _info("got on_auth_failure cb with reason $reason"); + $client->send_end_stream(); +} + +function on_chat_message($client, $stanza) { + // echo back incoming chat message stanza + $stanza->to = $stanza->from; + $stanza->from = $client->full_jid->to_string(); + $client->send($stanza); +} + +function on_presence_stanza($client, $stanza) { + global $client; + + $type = ($stanza->type ? $stanza->type : "available"); + $show = ($stanza->show ? $stanza->show : "???"); + _info($stanza->from." is now ".$type." ($show)"); + + if($type == "available") { + // fetch vcard + $client->get_vcard($stanza->from); + } +} + +function on_disconnect($client) { + _info("got on_disconnect cb"); +} + +// +// bootstrap all account instances +// + +foreach($accounts as $account) { + $client = new JAXL(array( + 'jid' => $account[0], + 'pass' => $account[1], + 'log_level' => JAXL_DEBUG + )); + + $client->add_cb('on_auth_success', 'on_auth_success'); + $client->add_cb('on_auth_failure', 'on_auth_failure'); + $client->add_cb('on_chat_message', 'on_chat_message'); + $client->add_cb('on_presence_stanza', 'on_presence_stanza'); + $client->add_cb('on_disconnect', 'on_disconnect'); + + $client->connect($client->get_socket_path()); + $client->start_stream(); +} + +// start core loop +JAXLLoop::run(); +echo "done\n"; + +?> Index: externals/JAXL/examples/pipes.php =================================================================== --- /dev/null +++ externals/JAXL/examples/pipes.php @@ -0,0 +1,59 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// include and configure logger +require_once 'jaxl.php'; +JAXLLogger::$level = JAXL_INFO; + +// include jaxl pipes +require_once JAXL_CWD.'/core/jaxl_pipe.php'; + +// initialize +$pipe_name = getmypid(); +$pipe = new JAXLPipe($pipe_name); + +// add read event callback +$pipe->set_callback(function($data) { + global $pipe; + _info("read ".trim($data)." from pipe"); +}); + +JAXLLoop::run(); +echo "done\n"; + +?> Index: externals/JAXL/examples/publisher.php =================================================================== --- /dev/null +++ externals/JAXL/examples/publisher.php @@ -0,0 +1,99 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 3) { + echo "Usage: $argv[0] jid pass\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + 'jid' => $argv[1], + 'pass' => $argv[2], + 'log_level' => JAXL_INFO +)); + +$client->require_xep(array( + '0060' // Publish-Subscribe +)); + +// +// add necessary event callbacks here +// + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + + // create node + //$client->xeps['0060']->create_node('pubsub.localhost', 'dummy_node'); + + // publish + $item = new JAXLXml('item', null, array('id'=>time())); + $item->c('entry', 'http://www.w3.org/2005/Atom'); + + $item->c('title')->t('Soliloquy')->up(); + $item->c('summary')->t('To be, or not to be: that is the question')->up(); + $item->c('link', null, array('rel'=>'alternate', 'type'=>'text/html', 'href'=>'http://denmark.lit/2003/12/13/atom03'))->up(); + $item->c('id')->t('tag:denmark.lit,2003:entry-32397')->up(); + $item->c('published')->t('2003-12-13T18:30:02Z')->up(); + $item->c('updated')->t('2003-12-13T18:30:02Z')->up(); + + $client->xeps['0060']->publish_item('pubsub.localhost', 'dummy_node', $item); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + $client->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/register_user.php =================================================================== --- /dev/null +++ externals/JAXL/examples/register_user.php @@ -0,0 +1,169 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 2) { + echo "Usage: $argv[0] domain\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + 'jid' => $argv[1], + 'log_level' => JAXL_DEBUG +)); + +$client->require_xep(array( + '0077' // InBand Registration +)); + +// +// below are two states which become part of +// our client's xmpp_stream lifecycle +// consider as if these methods are directly +// inside xmpp_stream state machine +// +// Note: $stanza = $args[0] is an instance of +// JAXLXml in xmpp_stream state methods, +// it is yet not ready for easy access +// patterns available on XMPPStanza instances +// + +$form = array(); + +function wait_for_register_response($event, $args) { + global $client, $form; + + if($event == 'stanza_cb') { + $stanza = $args[0]; + if($stanza->name == 'iq') { + $form['type'] = $stanza->attrs['type']; + if($stanza->attrs['type'] == 'result') { + echo "registration successful".PHP_EOL."shutting down...".PHP_EOL; + $client->send_end_stream(); + return "logged_out"; + } + else if($stanza->attrs['type'] == 'error') { + $error = $stanza->exists('error'); + echo "registration failed with error code: ".$error->attrs['code']." and type: ".$error->attrs['type'].PHP_EOL; + echo "error text: ".$error->exists('text')->text.PHP_EOL; + echo "shutting down...".PHP_EOL; + $client->send_end_stream(); + return "logged_out"; + } + } + } + else { + _notice("unhandled event $event rcvd"); + } +} + +function wait_for_register_form($event, $args) { + global $client, $form; + + $stanza = $args[0]; + $query = $stanza->exists('query', NS_INBAND_REGISTER); + if($query) { + $instructions = $query->exists('instructions'); + if($instructions) { + echo $instructions->text.PHP_EOL; + } + + foreach($query->childrens as $k=>$child) { + if($child->name != 'instructions') { + $form[$child->name] = readline($child->name.":"); + + } + } + + $client->xeps['0077']->set_form($stanza->attrs['from'], $form); + return "wait_for_register_response"; + } + else { + $client->end_stream(); + return "logged_out"; + } +} + +// +// add necessary event callbacks here +// + +$client->add_cb('on_stream_features', function($stanza) { + global $client, $argv; + $client->xeps['0077']->get_form($argv[1]); + return "wait_for_register_form"; +}); + +$client->add_cb('on_disconnect', function() { + global $form; + _info("registration " . ($form['type'] == 'result' ? 'succeeded' : 'failed')); +}); + +// +// finally start configured xmpp stream +// +$client->start(); + +// +// if registration was successful +// try to connect with newly registered account +// +if($form['type'] == 'result') { + +_info("connecting newly registered user account"); +$client = new JAXL(array( + 'jid' => $form['username'].'@'.$argv[1], + 'pass' => $form['password'], + 'log_level' => JAXL_DEBUG +)); + +$client->add_cb('on_auth_success', function() { + global $client; + $client->set_status('Available'); +}); + +$client->start(); + +} + +echo "done\n"; + +?> Index: externals/JAXL/examples/subscriber.php =================================================================== --- /dev/null +++ externals/JAXL/examples/subscriber.php @@ -0,0 +1,99 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc < 3) { + echo "Usage: $argv[0] jid pass\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + 'jid' => $argv[1], + 'pass' => $argv[2], + 'log_level' => JAXL_INFO +)); + +$client->require_xep(array( + '0060' // Publish-Subscribe +)); + +// +// add necessary event callbacks here +// + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + + // create node + //$client->xeps['0060']->create_node('pubsub.localhost', 'dummy_node'); + + // subscribe + $client->xeps['0060']->subscribe('pubsub.localhost', 'dummy_node'); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + $client->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$client->add_cb('on_headline_message', function($stanza) { + global $client; + if(($event = $stanza->exists('event', NS_PUBSUB.'#event'))) { + _info("got pubsub event"); + } + else { + _warning("unknown headline message rcvd"); + } +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/xfacebook_platform_client.php =================================================================== --- /dev/null +++ externals/JAXL/examples/xfacebook_platform_client.php @@ -0,0 +1,100 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc != 4) { + echo "Usage: $argv[0] fb_user_id_or_username fb_app_key fb_access_token\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + // (required) credentials + 'jid' => $argv[1].'@chat.facebook.com', + 'fb_app_key' => $argv[2], + 'fb_access_token' => $argv[3], + + // force tls (facebook require this now) + 'force_tls' => true, + // (required) force facebook oauth + 'auth_type' => 'X-FACEBOOK-PLATFORM', + + // (optional) + //'resource' => 'resource', + + 'log_level' => JAXL_INFO +)); + +// +// add necessary event callbacks here +// + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + $client->set_status("available!", "dnd", 10); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + $client->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$client->add_cb('on_chat_message', function($stanza) { + global $client; + + // echo back incoming message stanza + $stanza->to = $stanza->from; + $stanza->from = $client->full_jid->to_string(); + $client->send($stanza); +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/examples/xmpp_rest.php =================================================================== --- /dev/null +++ externals/JAXL/examples/xmpp_rest.php @@ -0,0 +1,77 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// View explanation for this example here: +// https://groups.google.com/d/msg/jaxl/QaGjZP4A2gY/n6SYutrBVxsJ +if($argc < 3) { + echo "Usage: $argv[0] jid pass\n"; + exit; +} + +// initialize xmpp client +require_once 'jaxl.php'; +$xmpp = new JAXL(array( + 'jid' => $argv[1], + 'pass' => $argv[2], + 'log_level' => JAXL_INFO +)); + +// register callbacks on required xmpp events +$xmpp->add_cb('on_auth_success', function() { + global $xmpp; + _info("got on_auth_success cb, jid ".$xmpp->full_jid->to_string()); +}); + +// initialize http server +require_once JAXL_CWD.'/http/http_server.php'; +$http = new HTTPServer(); + +// add generic callback +// you can also dispatch REST style callback +// Refer: http://jaxl.readthedocs.org/en/latest/users/http_extensions.html#dispatch-rules +$http->cb = function($request) { + // For demo purposes we simply return xmpp client full jid + global $xmpp; + $request->ok($xmpp->full_jid->to_string()); +}; + +// This will start main JAXLLoop, +// hence we don't need to call $http->start() explicitly +$xmpp->start(); + +?> Index: externals/JAXL/examples/xoauth2_gtalk_client.php =================================================================== --- /dev/null +++ externals/JAXL/examples/xoauth2_gtalk_client.php @@ -0,0 +1,99 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +if($argc != 3) { + echo "Usage: $argv[0] jid access_token\n"; + exit; +} + +// +// initialize JAXL object with initial config +// +require_once 'jaxl.php'; +$client = new JAXL(array( + // (required) credentials + 'jid' => $argv[1], + 'pass' => $argv[2], + + // force tls + 'force_tls' => true, + // (required) perform X-OAUTH2 + 'auth_type' => 'X-OAUTH2', + + // (optional) + //'resource' => 'resource', + + 'log_level' => JAXL_DEBUG +)); + +// +// add necessary event callbacks here +// + +$client->add_cb('on_auth_success', function() { + global $client; + _info("got on_auth_success cb, jid ".$client->full_jid->to_string()); + $client->set_status("available!", "dnd", 10); +}); + +$client->add_cb('on_auth_failure', function($reason) { + global $client; + $client->send_end_stream(); + _info("got on_auth_failure cb with reason $reason"); +}); + +$client->add_cb('on_chat_message', function($stanza) { + global $client; + + // echo back incoming message stanza + $stanza->to = $stanza->from; + $stanza->from = $client->full_jid->to_string(); + $client->send($stanza); +}); + +$client->add_cb('on_disconnect', function() { + _info("got on_disconnect cb"); +}); + +// +// finally start configured xmpp stream +// +$client->start(); +echo "done\n"; + +?> Index: externals/JAXL/http/README.md =================================================================== --- /dev/null +++ externals/JAXL/http/README.md @@ -0,0 +1,9 @@ +Jaxl HTTP Stack: +---------------- +HTTP Stack implementation includes: + +* HTTPClient - Generic HTTP Client +* HTTPServer - Generic HTTP Server +* HTTPRequest - A HTTP Request Object +* HTTPDispatcher - HTTP REST Url Dispatcher +* HTTPMultiPart - HTTP MultiPart Body \ No newline at end of file Index: externals/JAXL/http/http_client.php =================================================================== --- /dev/null +++ externals/JAXL/http/http_client.php @@ -0,0 +1,138 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_socket_client.php'; + +/** + * TODO: convert into a finite state machine + * + * @author abhinavsingh + * + */ +class HTTPClient { + + private $url = null; + private $parts = array(); + + private $headers = array(); + private $data = null; + public $method = null; + + private $client = null; + + public function __construct($url, $headers=array(), $data=null) { + $this->url = $url; + $this->headers = $headers; + $this->data = $data; + + $this->client = new JAXLSocketClient(); + $this->client->set_callback(array(&$this, 'on_response')); + } + + public function start($method='GET') { + $this->method = $method; + + $this->parts = parse_url($this->url); + $transport = $this->_transport(); + $ip = $this->_ip(); + $port = $this->_port(); + + $socket_path = $transport.'://'.$ip.':'.$port; + if($this->client->connect($socket_path)) { + _debug("connection to $this->url established"); + + // send request data + $this->send_request(); + + // start main loop + JAXLLoop::run(); + } + else { + _debug("unable to open $this->url"); + } + } + + public function on_response($raw) { + _info("got http response"); + } + + protected function send_request() { + $this->client->send($this->_line()."\r\n"); + $this->client->send($this->_ua()."\r\n"); + $this->client->send($this->_host()."\r\n"); + $this->client->send("\r\n"); + } + + // + // private methods on uri parts + // + + private function _line() { + return $this->method.' '.$this->_uri().' HTTP/1.1'; + } + + private function _ua() { + return 'User-Agent: jaxl_http_client/3.x'; + } + + private function _host() { + return 'Host: '.$this->parts['host'].':'.$this->_port(); + } + + private function _transport() { + return ($this->parts['scheme'] == 'http' ? 'tcp' : 'ssl'); + } + + private function _ip() { + return gethostbyname($this->parts['host']); + } + + private function _port() { + return @$this->parts['port'] ? $this->parts['port'] : 80; + } + + private function _uri() { + $uri = $this->parts['path']; + if(@$this->parts['query']) $uri .= '?'.$this->parts['query']; + if(@$this->parts['fragment']) $uri .= '#'.$this->parts['fragment']; + return $uri; + } + +} + +?> Index: externals/JAXL/http/http_dispatcher.php =================================================================== --- /dev/null +++ externals/JAXL/http/http_dispatcher.php @@ -0,0 +1,121 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// +// (optionally) set an array of url dispatch rules +// each dispatch rule is defined by an array of size 4 like: +// array($callback, $pattern, $methods, $extra), where +// $callback the method which will be called if this rule matches +// $pattern regular expression to match request path +// $methods list of allowed methods for this rule +// pass boolean true to allow all http methods +// if omitted or an empty array() is passed (which actually doesnt make sense) +// by default 'GET' will be the method allowed on this rule +// $extra reserved for future (you can totally omit this as of now) +// +class HTTPDispatchRule { + + // match callback + public $cb = null; + + // regexp to match on request path + public $pattern = null; + + // methods to match upon + // add atleast 1 method for this rule to work + public $methods = null; + + // other matching rules + public $extra = array(); + + public function __construct($cb, $pattern, $methods=array('GET'), $extra=array()) { + $this->cb = $cb; + $this->pattern = $pattern; + $this->methods = $methods; + $this->extra = $extra; + } + + public function match($path, $method) { + if(preg_match("/".str_replace("/", "\/", $this->pattern)."/", $path, $matches)) { + if(in_array($method, $this->methods)) { + return $matches; + } + } + return false; + } + +} + +class HTTPDispatcher { + + protected $rules = array(); + + public function __construct() { + $this->rules = array(); + } + + public function add_rule($rule) { + $s = sizeof($rule); + if($s > 4) { _debug("invalid rule"); return; } + + // fill up defaults + if($s == 3) { $rule[] = array(); } + else if($s == 2) { $rule[] = array('GET'); $rule[] = array(); } + else { _debug("invalid rule"); return; } + + $this->rules[] = new HTTPDispatchRule($rule[0], $rule[1], $rule[2], $rule[3]); + } + + public function dispatch($request) { + foreach($this->rules as $rule) { + //_debug("matching $request->path with pattern $rule->pattern"); + if(($matches = $rule->match($request->path, $request->method)) !== false) { + _debug("matching rule found, dispatching"); + $params = array($request); + // TODO: a bad way to restrict on 'pk', fix me for generalization + if(@isset($matches['pk'])) $params[] = $matches['pk']; + call_user_func_array($rule->cb, $params); + return true; + } + } + return false; + } + +} + +?> Index: externals/JAXL/http/http_multipart.php =================================================================== --- /dev/null +++ externals/JAXL/http/http_multipart.php @@ -0,0 +1,176 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_fsm.php'; + +class HTTPMultiPart extends JAXLFsm { + + public $boundary = null; + public $form_data = array(); + public $index = -1; + + public function handle_invalid_state($r) { + _error("got invalid event $r"); + } + + public function __construct($boundary) { + $this->boundary = $boundary; + parent::__construct('wait_for_boundary_start'); + } + + public function state() { + return $this->state; + } + + public function wait_for_boundary_start($event, $data) { + if($event == 'process') { + if($data[0] == '--'.$this->boundary) { + $this->index += 1; + $this->form_data[$this->index] = array( + 'meta' => array(), + 'headers' => array(), + 'body' => '' + ); + return array('wait_for_content_disposition', true); + } + else { + _warning("invalid boundary start $data[0] while expecting $this->boundary"); + return array('wait_for_boundary_start', false); + } + } + else { + _warning("invalid $event rcvd"); + return array('wait_for_boundary_start', false); + } + } + + public function wait_for_content_disposition($event, $data) { + if($event == 'process') { + $disposition = explode(":", $data[0]); + + if(strtolower(trim($disposition[0])) == 'content-disposition') { + $this->form_data[$this->index]['headers'][$disposition[0]] = trim($disposition[1]); + $meta = explode(";", $disposition[1]); + if(trim(array_shift($meta)) == 'form-data') { + foreach($meta as $k) { + list($k, $v) = explode("=", $k); + $this->form_data[$this->index]['meta'][$k] = $v; + } + + return array('wait_for_content_type', true); + } + else { + _warning("first part of meta is not form-data"); + return array('wait_for_content_disposition', false); + } + } + else { + _warning("not a valid content-disposition line"); + return array('wait_for_content_disposition', false); + } + } + else { + _warning("invalid $event rcvd"); + return array('wait_for_content_disposition', false); + } + } + + public function wait_for_content_type($event, $data) { + if($event == 'process') { + $type = explode(":", $data[0]); + if(strtolower(trim($type[0])) == 'content-type') { + $this->form_data[$this->index]['headers'][$type[0]] = trim($type[1]); + $this->form_data[$this->index]['meta']['type'] = $type[1]; + return array('wait_for_content_body', true); + } + else { + _debug("not a valid content-type line"); + return array('wait_for_content_type', false); + } + } + else { + _warning("invalid $event rcvd"); + return array('wait_for_content_type', false); + } + } + + public function wait_for_content_body($event, $data) { + if($event == 'process') { + if($data[0] == '--'.$this->boundary) { + _debug("start of new multipart/form-data detected"); + return array('wait_for_content_disposition', true); + } + else if($data[0] == '--'.$this->boundary.'--') { + _debug("end of multipart form data detected"); + return array('wait_for_empty_line', true); + } + else { + $this->form_data[$this->index]['body'] .= $data[0]; + return array('wait_for_content_body', true); + } + } + else { + _warning("invalid $event rcvd"); + return array('wait_for_content_body', false); + } + } + + public function wait_for_empty_line($event, $data) { + if($event == 'process') { + if($data[0] == '') { + return array('done', true); + } + else { + _warning("invalid empty line $data[0] received"); + return array('wait_for_empty_line', false); + } + } + else { + _warning("got $event in done state with data $data[0]"); + return array('wait_for_empty_line', false); + } + } + + public function done($event, $data) { + _warning("got unhandled event $event with data $data[0]"); + return array('done', false); + } + +} + +?> Index: externals/JAXL/http/http_request.php =================================================================== --- /dev/null +++ externals/JAXL/http/http_request.php @@ -0,0 +1,492 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_fsm.php'; +require_once JAXL_CWD.'/http/http_multipart.php'; + +// +// These methods are available only once +// $request FSM has reached 'headers_received' state +// +// following shortcuts are available +// on received $request object: +// +// $request->{status_code_name}($headers, $body) +// $request->{status_code_name}($body, $headers) +// +// $request->{status_code_name}($headers) +// $request->{status_code_name}($body) +// +// following specific methods are also available: +// +// $request->send_line($code) +// $request->send_header($key, $value) +// $request->send_headers($headers) +// $request->send_message($string) +// +// all the above methods can also be directly performed using: +// +// $request->send_response($code, $headers=array(), $body=null) +// +// Note: All the send_* methods do not manage connection close/keep-alive logic, +// it is upto you to do that, by default connection will usually be dropped +// on client disconnect if not handled by you. +// +class HTTPRequest extends JAXLFsm { + + // peer identifier + public $sock = null; + public $ip = null; + public $port = null; + + // request line + public $version = null; + public $method = null; + public $resource = null; + public $path = null; + public $query = array(); + + // headers and body + public $headers = array(); + public $body = null; + public $recvd_body_len = 0; + + // is true if 'Expect: 100-Continue' + // request header has been seen + public $expect = false; + + // set if there is Content-Type: multipart/form-data; boundary=... + // header already seen + public $multipart = null; + + // callback for send/read/close actions on accepted sock + private $_send_cb = null; + private $_read_cb = null; + private $_close_cb = null; + + private $shortcuts = array( + 'ok' => 200, // 2xx + 'redirect' => 302, 'not_modified' => 304, // 3xx + 'not_found' => 404, 'bad_request' => 400, // 4xx + 'internal_error' => 500, // 5xx + 'recv_body' => true, 'close' => true // others + ); + + public function __construct($sock, $addr) { + $this->sock = $sock; + + $addr = explode(":", $addr); + $this->ip = $addr[0]; + if(sizeof($addr) == 2) { + $this->port = $addr[1]; + } + + parent::__construct("setup"); + } + + public function __destruct() { + _debug("http request going down in ".$this->state." state"); + } + + public function state() { + return $this->state; + } + + // + // abstract method implementation + // + + public function handle_invalid_state($r) { + _debug("handle invalid state called with"); + var_dump($r); + } + + // + // fsm States + // + + public function setup($event, $args) { + switch($event) { + case 'set_sock_cb': + $this->_send_cb = $args[0]; + $this->_read_cb = $args[1]; + $this->_close_cb = $args[2]; + return 'wait_for_request_line'; + break; + default: + _warning("uncatched $event"); + return 'setup'; + } + } + + public function wait_for_request_line($event, $args) { + switch($event) { + case 'line': + $this->_line($args[0], $args[1], $args[2]); + return 'wait_for_headers'; + break; + default: + _warning("uncatched $event"); + return 'wait_for_request_line'; + } + } + + public function wait_for_headers($event, $args) { + switch($event) { + case 'set_header': + $this->set_header($args[0], $args[1]); + return 'wait_for_headers'; + break; + case 'empty_line': + return 'maybe_headers_received'; + default: + _warning("uncatched $event"); + return 'wait_for_headers'; + } + } + + public function maybe_headers_received($event, $args) { + switch($event) { + case 'set_header': + $this->set_header($args[0], $args[1]); + return 'wait_for_headers'; + break; + case 'empty_line': + return 'headers_received'; + break; + case 'body': + return $this->wait_for_body($event, $args); + break; + default: + _warning("uncatched $event"); + return 'maybe_headers_received'; + } + } + + public function wait_for_body($event, $args) { + switch($event) { + case 'body': + $content_length = $this->headers['Content-Length']; + $rcvd = $args[0]; + $rcvd_len = strlen($rcvd); + $this->recvd_body_len += $rcvd_len; + + if($this->body === null) $this->body = $rcvd; + else $this->body .= $rcvd; + + if($this->multipart) { + // boundary start, content_disposition, form data, boundary start, ....., boundary end + // these define various states of a multipart/form-data + $form_data = explode("\r\n", $rcvd); + foreach($form_data as $data) { + //_debug("passing $data to multipart fsm"); + if(!$this->multipart->process($data)) { + _debug("multipart fsm returned false"); + $this->_close(); + return array('closed', false); + } + } + } + + if($this->recvd_body_len < $content_length && $this->multipart->state() != 'done') { + _debug("rcvd body len: $this->recvd_body_len/$content_length"); + return 'wait_for_body'; + } + else { + _debug("all data received, switching state for dispatch"); + return 'headers_received'; + } + break; + case 'set_header': + $content_length = $this->headers['Content-Length']; + $body = implode(":", $args); + $rcvd_len = strlen($body); + $this->recvd_body_len += $rcvd_len; + + if(!$this->multipart->process($body)) { + _debug("multipart fsm returned false"); + $this->_close(); + return array('closed', false); + } + + if($this->recvd_body_len < $content_length) { + _debug("rcvd body len: $this->recvd_body_len/$content_length"); + return 'wait_for_body'; + } + else { + _debug("all data received, switching state for dispatch"); + return 'headers_received'; + } + break; + case 'empty_line': + $content_length = $this->headers['Content-Length']; + + if(!$this->multipart->process('')) { + _debug("multipart fsm returned false"); + $this->_close(); + return array('closed', false); + } + + if($this->recvd_body_len < $content_length) { + _debug("rcvd body len: $this->recvd_body_len/$content_length"); + return 'wait_for_body'; + } + else { + _debug("all data received, switching state for dispatch"); + return 'headers_received'; + } + break; + default: + _warning("uncatched $event"); + return 'wait_for_body'; + } + } + + // headers and may be body received + public function headers_received($event, $args) { + switch($event) { + case 'empty_line': + return 'headers_received'; + break; + default: + if(substr($event, 0, 5) == 'send_') { + $protected = '_'.$event; + if(method_exists($this, $protected)) { + call_user_func_array(array(&$this, $protected), $args); + return 'headers_received'; + } + else { + _debug("non-existant method $event called"); + return 'headers_received'; + } + } + else if(@isset($this->shortcuts[$event])) { + return $this->handle_shortcut($event, $args); + } + else { + _warning("uncatched $event ".$args[0]); + return 'headers_received'; + } + } + } + + public function closed($event, $args) { + _warning("uncatched $event"); + } + + // sets input headers + // called internally for every header received + protected function set_header($k, $v) { + $k = trim($k); $v = ltrim($v); + + // is expect header? + if(strtolower($k) == 'expect' && strtolower($v) == '100-continue') { + $this->expect = true; + } + + // is multipart form data? + if(strtolower($k) == 'content-type') { + $ctype = explode(';', $v); + if(sizeof($ctype) == 2 && strtolower(trim($ctype[0])) == 'multipart/form-data') { + $boundary = explode('=', trim($ctype[1])); + if(strtolower(trim($boundary[0])) == 'boundary') { + _debug("multipart with boundary $boundary[1] detected"); + $this->multipart = new HTTPMultiPart(ltrim($boundary[1])); + } + } + } + + $this->headers[trim($k)] = trim($v); + } + + // shortcut handler + protected function handle_shortcut($event, $args) { + _debug("executing shortcut '$event'"); + switch($event) { + // http status code shortcuts + case 'ok': + case 'redirect': + case 'not_modified': + case 'bad_request': + case 'not_found': + case 'internal_error': + list($headers, $body) = $this->parse_shortcut_args($args); + + $code = $this->shortcuts[$event]; + $this->_send_response($code, $headers, $body); + + $this->_close(); + return 'closed'; + break; + // others + case 'recv_body': + // send expect header if required + if($this->expect) { + $this->expect = false; + $this->_send_line(100); + } + + // read data + $this->_read(); + + return 'wait_for_body'; + break; + case 'close': + $this->_close(); + return 'closed'; + break; + } + } + + private function parse_shortcut_args($args) { + if(sizeof($args) == 0) { + $body = null; + $headers = array(); + } + if(sizeof($args) == 1) { + // http headers or body only received + if(is_array($args[0])) { + // http headers only + $headers = $args[0]; + $body = null; + } + else { + // body only + $body = $args[0]; + $headers = array(); + } + } + else if(sizeof($args) == 2) { + // body and http headers both received + if(is_array($args[0])) { + // header first + $body = $args[1]; + $headers = $args[0]; + } + else { + // body first + $body = $args[0]; + $headers = $args[1]; + } + } + + return array($headers, $body); + } + + // + // send methods + // available only on 'headers_received' state + // + + protected function _send_line($code) { + $raw = $this->version." ".$code." ".constant('HTTP_'.$code).HTTP_CRLF; + $this->_send($raw); + } + + protected function _send_header($k, $v) { + $raw = $k.': '.$v.HTTP_CRLF; + $this->_send($raw); + } + + protected function _send_headers($code, $headers) { + foreach($headers as $k=>$v) + $this->_send_header($k, $v); + } + + protected function _send_body($body) { + $this->_send($body); + } + + protected function _send_response($code, $headers=array(), $body=null) { + // send out response line + $this->_send_line($code); + + // set content length of body exists and is not already set + if($body && !isset($headers['Content-Length'])) + $headers['Content-Length'] = strlen($body); + + // send out headers + $this->_send_headers($code, $headers); + + // send body + // prefixed with an empty line + _debug("sending out HTTP_CRLF prefixed body"); + if($body) + $this->_send_body(HTTP_CRLF.$body); + } + + // + // internal methods + // + + // initializes status line elements + private function _line($method, $resource, $version) { + $this->method = $method; + $this->resource = $resource; + + $resource = explode("?", $resource); + $this->path = $resource[0]; + if(sizeof($resource) == 2) { + $query = $resource[1]; + $query = explode("&", $query); + foreach($query as $q) { + $q = explode("=", $q); + if(sizeof($q) == 1) $q[1] = ""; + $this->query[$q[0]] = $q[1]; + } + } + + $this->version = $version; + } + + private function _send($raw) { + call_user_func($this->_send_cb, $this->sock, $raw); + } + + private function _read() { + call_user_func($this->_read_cb, $this->sock); + } + + private function _close() { + call_user_func($this->_close_cb, $this->sock); + } + + +} + +?> Index: externals/JAXL/http/http_server.php =================================================================== --- /dev/null +++ externals/JAXL/http/http_server.php @@ -0,0 +1,197 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/core/jaxl_logger.php'; +require_once JAXL_CWD.'/http/http_dispatcher.php'; +require_once JAXL_CWD.'/http/http_request.php'; + +// carriage return and line feed +define('HTTP_CRLF', "\r\n"); + +// 1xx informational +define('HTTP_100', "Continue"); +define('HTTP_101', "Switching Protocols"); + +// 2xx success +define('HTTP_200', "OK"); + +// 3xx redirection +define('HTTP_301', 'Moved Permanently'); +define('HTTP_304', 'Not Modified'); + +// 4xx client error +define('HTTP_400', 'Bad Request'); +define('HTTP_403', 'Forbidden'); +define('HTTP_404', 'Not Found'); +define('HTTP_405', 'Method Not Allowed'); +define('HTTP_499', 'Client Closed Request'); // Nginx + +// 5xx server error +define('HTTP_500', 'Internal Server Error'); +define('HTTP_503', 'Service Unavailable'); + +class HTTPServer { + + private $server = null; + public $cb = null; + + private $dispatcher = null; + private $requests = array(); + + public function __construct($port=9699, $address="127.0.0.1") { + $path = 'tcp://'.$address.':'.$port; + + $this->server = new JAXLSocketServer( + $path, + array(&$this, 'on_accept'), + array(&$this, 'on_request') + ); + + $this->dispatcher = new HTTPDispatcher(); + } + + public function __destruct() { + $this->server = null; + } + + public function dispatch($rules) { + foreach($rules as $rule) { + $this->dispatcher->add_rule($rule); + } + } + + public function start($cb=null) { + $this->cb = $cb; + JAXLLoop::run(); + } + + public function on_accept($sock, $addr) { + _debug("on_accept for client#$sock, addr:$addr"); + + // initialize new request obj + $request = new HTTPRequest($sock, $addr); + + // setup sock cb + $request->set_sock_cb( + array(&$this->server, 'send'), + array(&$this->server, 'read'), + array(&$this->server, 'close') + ); + + // cache request object + $this->requests[$sock] = &$request; + + // reactive client for further read + $this->server->read($sock); + } + + public function on_request($sock, $raw) { + _debug("on_request for client#$sock"); + $request = $this->requests[$sock]; + + // 'wait_for_body' state is reached when ever + // application calls recv_body() method + // on received $request object + if($request->state() == 'wait_for_body') { + $request->body($raw); + } + else { + // break on crlf + $lines = explode(HTTP_CRLF, $raw); + + // parse request line + if($request->state() == 'wait_for_request_line') { + list($method, $resource, $version) = explode(" ", $lines[0]); + $request->line($method, $resource, $version); + unset($lines[0]); + _info($request->ip." ".$request->method." ".$request->resource." ".$request->version); + } + + // parse headers + foreach($lines as $line) { + $line_parts = explode(":", $line); + + if(sizeof($line_parts) > 1) { + if(strlen($line_parts[0]) > 0) { + $k = $line_parts[0]; + unset($line_parts[0]); + $v = implode(":", $line_parts); + $request->set_header($k, $v); + } + } + else if(strlen(trim($line_parts[0])) == 0) { + $request->empty_line(); + } + // if exploded line array size is 1 + // and thr is something in $line_parts[0] + // must be request body + else { + $request->body($line); + } + } + } + + // if request has reached 'headers_received' state? + if($request->state() == 'headers_received') { + // dispatch to any matching rule found + _debug("delegating to dispatcher for further routing"); + $dispatched = $this->dispatcher->dispatch($request); + + // if no dispatch rule matched call generic callback + if(!$dispatched && $this->cb) { + _debug("no dispatch rule matched, sending to generic callback"); + call_user_func($this->cb, $request); + } + // else if not dispatched and not generic callbacked + // send 404 not_found + else if(!$dispatched) { + // TODO: send 404 if no callback is registered for this request + _debug("dropping request since no matching dispatch rule or generic callback was specified"); + $request->not_found('404 Not Found'); + } + } + // if state is not 'headers_received' + // reactivate client socket for read event + else { + $this->server->read($sock); + } + } + +} + +?> Index: externals/JAXL/jaxl.php =================================================================== --- /dev/null +++ externals/JAXL/jaxl.php @@ -0,0 +1,809 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +date_default_timezone_set("UTC"); +declare(ticks = 1); +define('JAXL_CWD', dirname(__FILE__)); + +require_once JAXL_CWD.'/core/jaxl_exception.php'; +require_once JAXL_CWD.'/core/jaxl_cli.php'; +require_once JAXL_CWD.'/core/jaxl_loop.php'; +require_once JAXL_CWD.'/xmpp/xmpp_stream.php'; +require_once JAXL_CWD.'/xmpp/xmpp_roster_item.php'; +require_once JAXL_CWD.'/core/jaxl_event.php'; +require_once JAXL_CWD.'/core/jaxl_logger.php'; +require_once JAXL_CWD.'/core/jaxl_socket_server.php'; + +/** + * Jaxl class extends base XMPPStream class with following functionalities: + * 1) Adds an event based wrapper over xmpp stream lifecycle + * 2) Provides restart strategy and signal handling to ensure connectivity of xmpp stream + * 3) Roster management as specified in XMPP-IM + * 4) Management of XEP's inside xmpp stream lifecycle + * 5) Adds a logging facility + * 6) Adds a cron job facility in sync with connected xmpp stream timeline + * + * @author abhinavsingh + * + */ +class JAXL extends XMPPStream { + + // lib meta info + const version = '3.0.1'; + const name = 'JAXL :: Jabber XMPP Library'; + + // cached init config array + public $cfg = array(); + + // event callback engine for xmpp stream lifecycle + protected $ev = null; + + // reference to various xep instance objects + public $xeps = array(); + + // local cache of roster list + public $roster = array(); + + // whether jaxl must also populate local roster cache with + // received presence information about the contacts + public $manage_roster = true; + + // what to do with presence sub requests + // "none" | "accept" | "mutual" + public $manage_subscribe = "none"; + + // path variables + public $log_level = JAXL_INFO; + public $priv_dir; + public $tmp_dir; + public $log_dir; + public $pid_dir; + public $sock_dir; + + // ipc utils + private $sock; + private $cli; + + // env + public $local_ip; + public $pid; + public $mode; + + // current status message + public $status; + + // identity + public $features = array(); + public $category = 'client'; + public $type = 'bot'; + public $lang = 'en'; + + // after cth failed attempt + // retry connect after k * $retry_interval seconds + // where k is a random number between 0 and 2^c - 1. + public $retry = true; + private $retry_interval = 1; + private $retry_attempt = 0; + private $retry_max_interval = 32; // 2^5 seconds (means 5 max tries) + + public function __construct($config) { + $this->cfg = $config; + + // setup logger + if(isset($this->cfg['log_path'])) JAXLLogger::$path = $this->cfg['log_path']; + //else JAXLLogger::$path = $this->log_dir."/jaxl.log"; + if(isset($this->cfg['log_level'])) JAXLLogger::$level = $this->log_level = $this->cfg['log_level']; + else JAXLLogger::$level = $this->log_level; + + // env + $strict = isset($this->cfg['strict']) ? $this->cfg['strict'] : TRUE; + if($strict) $this->add_exception_handlers(); + $this->mode = PHP_SAPI; + $this->local_ip = gethostbyname(php_uname('n')); + $this->pid = getmypid(); + + // jid object + $jid = @$this->cfg['jid'] ? new XMPPJid($this->cfg['jid']) : null; + + // handle signals + if(extension_loaded('pcntl')) { + pcntl_signal(SIGHUP, array($this, 'signal_handler')); + pcntl_signal(SIGINT, array($this, 'signal_handler')); + pcntl_signal(SIGTERM, array($this, 'signal_handler')); + } + + // create .jaxl directory in JAXL_CWD + // for our /tmp, /run and /log folders + // overwrite these using jaxl config array + $this->priv_dir = @$this->cfg['priv_dir'] ? $this->cfg['priv_dir'] : JAXL_CWD."/.jaxl"; + $this->tmp_dir = $this->priv_dir."/tmp"; + $this->pid_dir = $this->priv_dir."/run"; + $this->log_dir = $this->priv_dir."/log"; + $this->sock_dir = $this->priv_dir."/sock"; + if(!is_dir($this->priv_dir)) mkdir($this->priv_dir); + if(!is_dir($this->tmp_dir)) mkdir($this->tmp_dir); + if(!is_dir($this->pid_dir)) mkdir($this->pid_dir); + if(!is_dir($this->log_dir)) mkdir($this->log_dir); + if(!is_dir($this->sock_dir)) mkdir($this->sock_dir); + + // touch pid file + if($this->mode == "cli") { + touch($this->get_pid_file_path()); + _info("created pid file ".$this->get_pid_file_path()); + } + + // include mandatory xmpp xeps + // service discovery and entity caps + // are recommended for every xmpp entity + $this->require_xep(array('0030', '0115')); + + // do dns lookup, update $cfg['host'] and $cfg['port'] if not already specified + $host = @$this->cfg['host']; + $port = @$this->cfg['port']; + if((!$host || !$port) && $jid) { + // this dns lookup is blocking + _info("dns srv lookup for ".$jid->domain); + list($host, $port) = JAXLUtil::get_dns_srv($jid->domain); + } + $this->cfg['host'] = @$this->cfg['host'] ? $this->cfg['host'] : $host; + $this->cfg['port'] = @$this->cfg['port'] ? $this->cfg['port'] : $port; + + // choose appropriate transport + // if 'bosh_url' cfg is defined include 0206 + if(@$this->cfg['bosh_url']) { + _debug("including bosh xep"); + $this->require_xep('0206'); + $transport = $this->xeps['0206']; + } + else { + //list($host, $port) = JAXLUtil::get_dns_srv($jid->domain); + $stream_context = @$this->cfg['stream_context']; + $transport = new JAXLSocketClient($stream_context); + } + + // lifecycle events callback + $this->ev = new JAXLEvent(defined('JAXL_MULTI_CLIENT') ? array(&$this) : array()); + + // initialize xmpp stream with configured transport + parent::__construct( + $transport, + $jid, + @$this->cfg['pass'], + @$this->cfg['resource'] ? 'jaxl#'.$this->cfg['resource'] : 'jaxl#'.md5(time()), + @$this->cfg['force_tls'] + ); + } + + public function __destruct() { + // delete pid file + _info("cleaning up pid and unix sock files"); + @unlink($this->get_pid_file_path()); + @unlink($this->get_sock_file_path()); + + parent::__destruct(); + } + + public function add_exception_handlers() { + _info("strict mode enabled, adding exception handlers. Set 'strict'=>TRUE inside JAXL config to disable this"); + set_error_handler(array('JAXLException', 'error_handler')); + set_exception_handler(array('JAXLException', 'exception_handler')); + register_shutdown_function(array('JAXLException', 'shutdown_handler')); + } + + public function get_pid_file_path() { + return $this->pid_dir."/jaxl_".$this->pid.".pid"; + } + + public function get_sock_file_path() { + return $this->sock_dir."/jaxl_".$this->pid.".sock"; + } + + public function require_xep($xeps) { + if(!is_array($xeps)) + $xeps = array($xeps); + + foreach($xeps as $xep) { + $filename = 'xep_'.$xep.'.php'; + $classname = 'XEP_'.$xep; + + // include xep + require_once JAXL_CWD.'/xep/'.$filename; + $this->xeps[$xep] = new $classname($this); + + // add necessary requested callback on events + foreach($this->xeps[$xep]->init() as $ev=>$cb) { + $this->add_cb($ev, array($this->xeps[$xep], $cb)); + } + } + } + + public function add_cb($ev, $cb, $pri=1) { + return $this->ev->add($ev, $cb, $pri); + } + + public function del_cb($ref) { + $this->ev->del($ref); + } + + public function set_status($status, $show='chat', $priority=10) { + $this->send($this->get_pres_pkt( + array(), + $status, + $show, + $priority + )); + } + + public function send_chat_msg($to, $body, $thread=null, $subject=null) { + $msg = new XMPPMsg( + array( + 'type'=>'chat', + 'to'=>$to, + 'from'=>$this->full_jid->to_string() + ), + $body, + $thread, + $subject + ); + $this->send($msg); + } + + public function get_vcard($jid=null, $cb=null) { + $attrs = array( + 'type'=>'get', + 'from'=>$this->full_jid->to_string() + ); + + if($jid) { + $jid = new XMPPJid($jid); + $attrs['to'] = $jid->node."@".$jid->domain; + } + + $pkt = $this->get_iq_pkt( + $attrs, + new JAXLXml('vCard', 'vcard-temp') + ); + if($cb) $this->add_cb('on_stanza_id_'.$pkt->id, $cb); + $this->send($pkt); + } + + public function get_roster($cb=null) { + $pkt = $this->get_iq_pkt( + array( + 'type'=>'get', + 'from'=>$this->full_jid->to_string() + ), + new JAXLXml('query', 'jabber:iq:roster') + ); + if($cb) $this->add_cb('on_stanza_id_'.$pkt->id, $cb); + $this->send($pkt); + } + + public function subscribe($to) { + $this->send($this->get_pres_pkt( + array('to'=>$to, 'type'=>'subscribe') + )); + } + + public function subscribed($to) { + $this->send($this->get_pres_pkt( + array('to'=>$to, 'type'=>'subscribed') + )); + } + + public function unsubscribe($to) { + $this->send($this->get_pres_pkt( + array('to'=>$to, 'type'=>'unsubscribe') + )); + } + + public function unsubscribed($to) { + $this->send($this->get_pres_pkt( + array('to'=>$to, 'type'=>'unsubscribed') + )); + } + + public function get_socket_path() { + return ($this->cfg['port'] == 5223 ? "ssl" : "tcp")."://".$this->cfg['host'].":".$this->cfg['port']; + } + + public function retry() { + $retry_after = pow(2, $this->retry_attempt) * $this->retry_interval; + $this->retry_attempt++; + _info("Will try to restart in ".$retry_after." seconds"); + + // TODO: use jaxl cron if sigalarms cannnot be used + sleep($retry_after); + $this->start(); + } + + public function start($opts=array()) { + // is bosh bot? + if(@$this->cfg['bosh_url']) { + $this->trans->session_start(); + + for(;;) { + // while any of the curl request is pending + // keep receiving response + while(sizeof($this->trans->chs) != 0) { + $this->trans->recv(); + } + + // if no request in queue, ping bosh end point + // and repeat recv + $this->trans->ping(); + } + + $this->trans->session_end(); + return; + } + + // is xmpp client or component? + // if on_connect event have no callbacks + // set default on_connect callback to $this->start_stream() + // i.e. xmpp client mode + if(!$this->ev->exists('on_connect')) + $this->add_cb('on_connect', array($this, 'start_stream')); + + // connect to the destination host/port + if($this->connect($this->get_socket_path())) { + // reset in case we connected back after retries + $this->retry_attempt = 0; + + // emit + $this->ev->emit('on_connect'); + + // parse opts + if(@$opts['--with-debug-shell']) $this->enable_debug_shell(); + if(@$opts['--with-unix-sock']) $this->enable_unix_sock(); + + // run main loop + JAXLLoop::run(); + + // emit + $this->ev->emit('on_disconnect'); + } + // if connection to the destination fails + else { + if($this->trans->errno == 61 + || $this->trans->errno == 110 + || $this->trans->errno == 111 + ) { + _debug("unable to connect with errno ".$this->trans->errno." (".$this->trans->errstr.")"); + $this->retry(); + } + else { + $this->ev->emit('on_connect_error', array( + $this->trans->errno, + $this->trans->errstr + )); + } + } + } + + // + // callback methods + // + + // signals callback handler + // not for public api consumption + public function signal_handler($sig) { + $this->end_stream(); + $this->disconnect(); + $this->ev->emit('on_disconnect'); + + switch($sig) { + // terminal line hangup + case SIGHUP: + _debug("got sighup"); + break; + // interrupt program + case SIGINT: + _debug("got sigint"); + break; + // software termination signal + case SIGTERM: + _debug("got sigterm"); + break; + } + + exit; + } + + // called internally for ipc + // not for public consumption + public function on_unix_sock_accept($_c, $addr) { + $this->sock->read($_c); + } + + // this currently simply evals the incoming raw string + // know what you are doing while in production + public function on_unix_sock_request($_c, $_raw) { + _debug("evaling raw string rcvd over unix sock: ".$_raw); + $this->sock->send($_c, serialize(eval($_raw))); + $this->sock->read($_c); + } + + public function enable_unix_sock() { + $this->sock = new JAXLSocketServer( + 'unix://'.$this->get_sock_file_path(), + array(&$this, 'on_unix_sock_accept'), + array(&$this, 'on_unix_sock_request') + ); + } + + // this simply eval the incoming raw data + // inside current jaxl environment + // security is all upto you, no checks made here + public function handle_debug_shell($_raw) { + print_r(eval($_raw)); + echo PHP_EOL; + JAXLCli::prompt(); + } + + protected function enable_debug_shell() { + $this->cli = new JAXLCli(array(&$this, 'handle_debug_shell')); + JAXLCli::prompt(); + } + + // + // abstract method implementation + // + + protected function send_fb_challenge_response($challenge) { + $this->send($this->get_fb_challenge_response_pkt($challenge)); + } + + // refer https://developers.facebook.com/docs/chat/#jabber + public function get_fb_challenge_response_pkt($challenge) { + $stanza = new JAXLXml('response', NS_SASL); + + $challenge = base64_decode($challenge); + $challenge = urldecode($challenge); + parse_str($challenge, $challenge_arr); + + $response = http_build_query(array( + 'method' => $challenge_arr['method'], + 'nonce' => $challenge_arr['nonce'], + 'access_token' => $this->cfg['fb_access_token'], + 'api_key' => $this->cfg['fb_app_key'], + 'call_id' => 0, + 'v' => '1.0' + )); + + $stanza->t(base64_encode($response)); + return $stanza; + } + + public function wait_for_fb_sasl_response($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + if($stanza->name == 'challenge' && $stanza->ns == NS_SASL) { + $challenge = $stanza->text; + $this->send_fb_challenge_response($challenge); + return "wait_for_sasl_response"; + } + else { + _debug("got unhandled sasl response, should never happen here"); + exit; + } + break; + default: + _debug("not catched $event, should never happen here"); + exit; + break; + } + } + + // someday this needs to go inside xmpp stream + public function wait_for_cram_md5_response($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + if($stanza->name == 'challenge' && $stanza->ns == NS_SASL) { + $challenge = base64_decode($stanza->text); + $resp = new JAXLXml('response', NS_SASL); + $resp->t(base64_encode($this->jid->to_string().' '.hash_hmac('md5', $challenge, $this->pass))); + $this->send($resp); + return "wait_for_sasl_response"; + } + else { + _debug("got unhandled sasl response, should never happen here"); + exit; + } + break; + default: + _debug("not catched $event, should never happen here"); + exit; + break; + } + } + + // http://tools.ietf.org/html/rfc5802#section-5 + public function get_scram_sha1_response($pass, $challenge) { + // it contains users iteration count i and the user salt + // also server will append it's own nonce to the one we specified + $decoded = $this->explode_data(base64_decode($challenge)); + + // r=,s=,i= + $nonce = $decoded['r']; + $salt = base64_decode($decoded['s']); + $iteration = intval($decoded['i']); + + // SaltedPassword := Hi(Normalize(password), salt, i) + $salted = JAXLUtil::pbkdf2($this->pass, $salt, $iteration); + // ClientKey := HMAC(SaltedPassword, "Client Key") + $client_key = hash_hmac('sha1', $salted, "Client Key", true); + // StoredKey := H(ClientKey) + $stored_key = hash('sha1', $client_key, true); + // AuthMessage := client-first-message-bare + "," + server-first-message + "," + client-final-message-without-proof + $auth_message = ''; + // ClientSignature := HMAC(StoredKey, AuthMessage) + $signature = hash_hmac('sha1', $stored_key, $auth_message, true); + // ClientProof := ClientKey XOR ClientSignature + $client_proof = $client_key ^ $signature; + + $proof = 'c=biws,r='.$nonce.',p='.base64_encode($client_proof); + return base64_encode($proof); + } + + public function wait_for_scram_sha1_response($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + if($stanza->name == 'challenge' && $stanza->ns == NS_SASL) { + $challenge = $stanza->text; + + $resp = new JAXLXml('response', NS_SASL); + $resp->t($this->get_scram_sha1_response($this->pass, $challenge)); + $this->send($resp); + + return "wait_for_sasl_response"; + } + else { + _debug("got unhandled sasl response, should never happen here"); + exit; + } + break; + default: + _debug("not catched $event, should never happen here"); + exit; + break; + } + } + + public function handle_auth_mechs($stanza, $mechanisms) { + if($this->ev->exists('on_stream_features')) { + return $this->ev->emit('on_stream_features', array($stanza)); + } + + // extract available mechanisms + $mechs = array(); + if($mechanisms) foreach($mechanisms->childrens as $mechanism) $mechs[$mechanism->text] = true; + + // check if preferred auth type exists in available mechanisms + $pref_auth = @$this->cfg['auth_type'] ? $this->cfg['auth_type'] : 'PLAIN'; + $pref_auth_exists = isset($mechs[$pref_auth]) ? true : false; + _debug("pref_auth ".$pref_auth." ".($pref_auth_exists ? "exists" : "doesn't exists")); + + // if pref auth exists, try it + if($pref_auth_exists) { + $mech = $pref_auth; + } + // if pref auth doesn't exists, choose one from available mechanisms + else { + foreach($mechs as $mech=>$any) { + // choose X-FACEBOOK-PLATFORM only if fb_access_token config value is available + if($mech == 'X-FACEBOOK-PLATFORM') { + if(@$this->cfg['fb_access_token']) { + break; + } + } + // else try first of the available methods + else { + break; + } + } + _error("preferred auth type not supported, trying $mech"); + } + + $this->send_auth_pkt($mech, @$this->jid ? $this->jid->to_string() : null, @$this->pass); + + if($pref_auth == 'X-FACEBOOK-PLATFORM') { + return "wait_for_fb_sasl_response"; + } + else if($pref_auth == 'CRAM-MD5') { + return "wait_for_cram_md5_response"; + } + else if($pref_auth == 'SCRAM-SHA-1') { + return "wait_for_scram_sha1_response"; + } + } + + public function handle_auth_success() { + // if not a component + /*if(!@$this->xeps['0114']) { + $this->xeps['0030']->get_info($this->full_jid->domain, array(&$this, 'handle_domain_info')); + $this->xeps['0030']->get_items($this->full_jid->domain, array(&$this, 'handle_domain_items')); + }*/ + + $this->ev->emit('on_auth_success'); + } + + public function handle_auth_failure($reason) { + $this->ev->emit('on_auth_failure', array( + $reason + )); + } + + public function handle_stream_start($stanza) { + $stanza = new XMPPStanza($stanza); + + $this->ev->emit('on_stream_start', array($stanza)); + return array(@$this->cfg['bosh_url'] ? 'wait_for_stream_features' : 'connected', 1); + } + + public function handle_iq($stanza) { + $stanza = new XMPPStanza($stanza); + + // emit callback registered on stanza id's + $emited = false; + if($stanza->id && $this->ev->exists('on_stanza_id_'.$stanza->id)) { + //_debug("on stanza id callbackd"); + $emited = true; + $this->ev->emit('on_stanza_id_'.$stanza->id, array($stanza)); + } + + // catch roster list + if($stanza->type == 'result' && ($query = $stanza->exists('query', 'jabber:iq:roster'))) { + foreach($query->childrens as $child) { + if($child->name == 'item') { + $jid = $child->attrs['jid']; + $subscription = $child->attrs['subscription']; + + $groups = array(); + foreach($child->childrens as $group) { + if($group->name == 'group') { + $groups[] = $group->text; + } + } + + $this->roster[$jid] = new XMPPRosterItem($jid, $subscription, $groups); + } + } + + // emit this event if not emited above + if(!$emited) + $this->ev->emit('on_roster_update'); + } + + // if managing roster + // catch contact vcard results + if($this->manage_roster && $stanza->type == 'result' && ($query = $stanza->exists('vCard', 'vcard-temp'))) { + if(@$this->roster[$stanza->from]) + $this->roster[$stanza->from]->vcard = $query; + } + + // on_get_iq, on_result_iq, and other events are only + // emitted if on_stanza_id_{id} wasn't emitted above + // TODO: can we add more checks here before calling back + // e.g. checks on existence of an attribute, check on 1st level child ns and so on + if(!$emited) + $this->ev->emit('on_'.$stanza->type.'_iq', array($stanza)); + } + + public function handle_presence($stanza) { + $stanza = new XMPPStanza($stanza); + + // if managing roster + // catch available/unavailable type stanza + if($this->manage_roster) { + $type = ($stanza->type ? $stanza->type : "available"); + $jid = new XMPPJid($stanza->from); + + if($type == 'available') { + $this->roster[$jid->bare]->resources[$jid->resource] = $stanza; + } + else if($type == 'unavailable') { + if(@$this->roster[$jid->bare] && @$this->roster[$jid->bare]->resources[$jid->resource]) + unset($this->roster[$jid->bare]->resources[$jid->resource]); + } + } + + // if managing subscription requests + // we need to automate stuff here + if($stanza->type == "subscribe" && $this->manage_subscribe != "none") { + $this->subscribed($stanza->from); + if($this->manage_subscribe == "mutual") + $this->subscribe($stanza->from); + } + + $this->ev->emit('on_presence_stanza', array($stanza)); + } + + public function handle_message($stanza) { + $stanza = new XMPPStanza($stanza); + $stanza->type = (@$stanza->type ? $stanza->type : 'normal'); + $this->ev->emit('on_'.$stanza->type.'_message', array($stanza)); + } + + // unhandled event and arguments bubbled up + // TODO: in a lot of cases this will be called, need more checks + public function handle_other($event, $args) { + $stanza = $args[0]; + $stanza = new XMPPStanza($stanza); + $ev = 'on_'.$stanza->name.'_stanza'; + if($this->ev->exists($ev)) { + return $this->ev->emit($ev, array($stanza)); + } + else { + _warning("event '".$event."' catched in handle_other with stanza name ".$stanza->name); + } + } + + public function handle_domain_info($stanza) { + $query = $stanza->exists('query', NS_DISCO_INFO); + foreach($query->childrens as $k=>$child) { + if($child->name == 'identity') { + //echo 'identity category:'.@$child->attrs['category'].', type:'.@$child->attrs['type'].', name:'.@$child->attrs['name'].PHP_EOL; + } + else if($child->name == 'x') { + //echo 'x ns:'.$child->ns.PHP_EOL; + } + else if($child->name == 'feature') { + //echo 'feature var:'.$child->attrs['var'].PHP_EOL; + } + } + } + + public function handle_domain_items($stanza) { + $query = $stanza->exists('query', NS_DISCO_ITEMS); + foreach($query->childrens as $k=>$child) { + if($child->name == 'item') { + //echo 'item jid:'.@$child->attrs['jid'].', name:'.@$child->attrs['name'].', node:'.@$child->attrs['node'].PHP_EOL; + } + } + } + +} + +?> Index: externals/JAXL/jaxlctl =================================================================== --- /dev/null +++ externals/JAXL/jaxlctl @@ -0,0 +1,190 @@ +#!/usr/bin/env php +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +$params = $argv; +$exe = array_shift($params); +$command = array_shift($params); + +require_once 'jaxl.php'; +JAXLLogger::$level = JAXL_INFO; + +// TODO: an abstract JAXLCtlCommand class +// with seperate class per command +// a mechanism to register new commands +class JAXLCtl { + + protected $ipc = null; + + protected $buffer = ''; + protected $buffer_cb = null; + protected $cli = null; + public $dots = "....... "; + + protected $symbols = array(); + + public function __construct($command, $params) { + global $exe; + + if(method_exists(&$this, $command)) { + $r = call_user_func_array(array(&$this, $command), $params); + if(sizeof($r) == 2) { + list($buffer_cb, $quit_cb) = $r; + $this->buffer_cb = $buffer_cb; + $this->cli = new JAXLCli(array(&$this, 'on_terminal_input'), $quit_cb); + $this->run(); + } + else { + _colorize("oops! internal command error", JAXL_ERROR); + exit; + } + } + else { + _colorize("error: invalid command '$command' received", JAXL_ERROR); + _colorize("type '$exe help' for list of available commands", JAXL_NOTICE); + exit; + } + } + + public function run() { + JAXLCli::prompt(); + JAXLLoop::run(); + } + + public function on_terminal_input($raw) { + $raw = trim($raw); + $last = substr($raw, -1, 1); + + if($last == ";") { + // dispatch to buffer callback + call_user_func($this->buffer_cb, $this->buffer.$raw); + $this->buffer = ''; + } + else if($last == '\\') { + $this->buffer .= substr($raw, 0, -1); + echo $this->dots; + } + else { + // buffer command + $this->buffer .= $raw."; "; + echo $this->dots; + } + } + + public static function print_help() { + global $exe; + _colorize("Usage: $exe command [options...]\n", JAXL_INFO); + _colorize("Commands:", JAXL_NOTICE); + _colorize(" help This help text", JAXL_DEBUG); + _colorize(" debug Attach a debug console to a running JAXL daemon", JAXL_DEBUG); + _colorize(" shell Open up Jaxl shell emulator", JAXL_DEBUG); + echo "\n"; + } + + protected function help() { + JAXLCtl::print_help(); + exit; + } + + // + // shell command + // + + protected function shell() { + return array(array(&$this, 'on_shell_input'), array(&$this, 'on_shell_quit')); + } + + private function _eval($raw, $symbols) { + extract($symbols); + + eval($raw); + $g = get_defined_vars(); + + unset($g['raw']); + unset($g['symbols']); + return $g; + } + + public function on_shell_input($raw) { + $this->symbols = $this->_eval($raw, $this->symbols); + JAXLCli::prompt(); + } + + public function on_shell_quit() { + exit; + } + + // + // debug command + // + + protected function debug($sock_path) { + $this->ipc = new JAXLSocketClient(); + $this->ipc->set_callback(array(&$this, 'on_debug_response')); + $this->ipc->connect('unix://'.$sock_path); + return array(array(&$this, 'on_debug_input'), array(&$this, 'on_debug_quit')); + } + + public function on_debug_response($raw) { + $ret = unserialize($raw); + print_r($ret); + echo "\n"; + JAXLCli::prompt(); + } + + public function on_debug_input($raw) { + $this->ipc->send($this->buffer.$raw); + } + + public function on_debug_quit() { + $this->ipc->disconnect(); + exit; + } + +} + +// we atleast need a command argument +if($argc < 2) { + JAXLCtl::print_help(); + exit; +} + +$ctl = new JAXLCtl($command, $params); +echo "done\n"; + +?> Index: externals/JAXL/tests/test_jaxl_event.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_jaxl_event.php @@ -0,0 +1,72 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class JAXLEventTest extends PHPUnit_Framework_TestCase { + + function test_jaxl_event() { + $ev = new JAXLEvent(); + + $ref1 = $ev->add('on_connect', 'some_func', 0); + $ref2 = $ev->add('on_connect', 'some_func1', 0); + $ref3 = $ev->add('on_connect', 'some_func2', 1); + $ref4 = $ev->add('on_connect', 'some_func3', 4); + $ref5 = $ev->add('on_disconnect', 'some_func', 1); + $ref6 = $ev->add('on_disconnect', 'some_func1', 1); + + //$ev->emit('on_connect', null); + + $ev->del($ref2); + $ev->del($ref1); + $ev->del($ref6); + $ev->del($ref5); + $ev->del($ref4); + $ev->del($ref3); + + //print_r($ev->reg); + } + +} Index: externals/JAXL/tests/test_jaxl_socket_client.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_jaxl_socket_client.php @@ -0,0 +1,60 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class JAXLSocketClientTest extends PHPUnit_Framework_TestCase { + + function test_jaxl_socket_client() { + $sock = new JAXLSocketClient("127.0.0.1", 5222); + $sock->connect(); + + $sock->send(""); + while($sock->fd) { + $sock->recv(); + } + } + +} Index: externals/JAXL/tests/test_jaxl_xml_stream.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_jaxl_xml_stream.php @@ -0,0 +1,74 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class JAXLXmlStreamTest extends PHPUnit_Framework_TestCase { + + function xml_start_cb($node) { + $this->assertEquals('stream', $node->name); + $this->assertEquals(NS_XMPP, $node->ns); + } + + function xml_end_cb($node) { + $this->assertEquals('stream', $node->name); + } + + function xml_stanza_cb($node) { + $this->assertEquals('features', $node->name); + $this->assertEquals(1, sizeof($node->childrens)); + } + + function test_xml_stream_callbacks() { + $xml = new JAXLXmlStream(); + $xml->set_callback(array(&$this, "xml_start_cb"), array(&$this, "xml_end_cb"), array(&$this, "xml_stanza_cb")); + $xml->parse(''); + $xml->parse(''); + $xml->parse(''); + $xml->parse(''); + $xml->parse(''); + $xml->parse(''); + } +} Index: externals/JAXL/tests/test_xmpp_jid.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_xmpp_jid.php @@ -0,0 +1,63 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class XMPPJidTest extends PHPUnit_Framework_TestCase { + + function test_xmpp_jid_construct() { + $jid = new XMPPJid("1@domain.tld/res"); + $this->assertEquals('1@domain.tld/res', $jid->to_string()); + + $jid = new XMPPJid("domain.tld/res"); + $this->assertEquals('domain.tld/res', $jid->to_string()); + + $jid = new XMPPJid("component.domain.tld"); + $this->assertEquals('component.domain.tld', $jid->to_string()); + + $jid = new XMPPJid("1@domain.tld"); + $this->assertEquals('1@domain.tld', $jid->to_string()); + } +} Index: externals/JAXL/tests/test_xmpp_msg.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_xmpp_msg.php @@ -0,0 +1,68 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class XMPPMsgTest extends PHPUnit_Framework_TestCase { + + function test_xmpp_msg() { + $msg = new XMPPMsg(array('to'=>'2@w.c', 'from'=>'-0@q.p/~', 'type'=>'chat'), 'hi', 'thread1'); + + echo $msg->to.PHP_EOL; + echo $msg->to_node.PHP_EOL; + echo $msg->from.PHP_EOL; + echo $msg->to_string().PHP_EOL; + + $msg->to = '4@w.c/sp'; + $msg->body = 'hello world'; + $msg->subject = 'some subject'; + + echo $msg->to.PHP_EOL; + echo $msg->to_node.PHP_EOL; + echo $msg->from.PHP_EOL; + echo $msg->to_string().PHP_EOL; + } + +} Index: externals/JAXL/tests/test_xmpp_stanza.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_xmpp_stanza.php @@ -0,0 +1,76 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class XMPPStanzaTest extends PHPUnit_Framework_TestCase { + + function test_xmpp_stanza_nested() { + $stanza = new JAXLXml('message', array('to'=>'1@a.z', 'from'=>'2@b.c')); + $stanza + ->c('body')->attrs(array('xml:lang'=>'en'))->t('hello')->up() + ->c('thread')->t('1234')->up() + ->c('nested') + ->c('nest')->t('nest1')->up() + ->c('nest')->t('nest2')->up() + ->c('nest')->t('nest3')->up()->up() + ->c('c')->attrs(array('hash'=>'84jsdmnskd')); + + $this->assertEquals( + 'hello1234nest1nest2nest3', + $stanza->to_string() + ); + } + + function test_xmpp_stanza_from_jaxl_xml() { + // xml to stanza test + $xml = new JAXLXml('message', NS_JABBER_CLIENT, array('to'=>'2@3.com', 'from'=>'4@r.p/q')); + $stanza = new XMPPStanza($xml); + $stanza->c('body')->t('hello world'); + echo $stanza->to."\n"; + echo $stanza->to_string()."\n"; + } + +} Index: externals/JAXL/tests/test_xmpp_stream.php =================================================================== --- /dev/null +++ externals/JAXL/tests/test_xmpp_stream.php @@ -0,0 +1,60 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class XMPPStreamTest extends PHPUnit_Framework_TestCase { + + function test_xmpp_stream() { + $xmpp = new XMPPStream("test@localhost", "password"); + $xmpp->connect(); + + $xmpp->start_stream(); + while($xmpp->sock->fd) { + $xmpp->sock->recv(); + } + } + +} Index: externals/JAXL/tests/tests.php =================================================================== --- /dev/null +++ externals/JAXL/tests/tests.php @@ -0,0 +1,52 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// TODO: support for php unit and add more tests +error_reporting(E_ALL); +require_once "jaxl.php"; + +/** + * + * @author abhinavsingh + * + */ +class JAXLTest extends PHPUnit_Framework_TestCase { + +} + +?> Index: externals/JAXL/xep/README.md =================================================================== --- /dev/null +++ externals/JAXL/xep/README.md @@ -0,0 +1,14 @@ +Jaxl XMPP XEP's: +---------------- +Following XMPP Extensions are available: + +* 0030 - Service Discovery +* 0045 - Multi-User Chat +* 0060 - Publish-Subscribe +* 0077 - In-Band Registration +* 0114 - Jabber Component +* 0115 - Entity Capabilities +* 0199 - XMPP Ping +* 0203 - Delayed Delivery +* 0206 - XMPP Over BOSH +* 0249 - Direct MUC Invitation \ No newline at end of file Index: externals/JAXL/xep/xep_0030.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0030.php @@ -0,0 +1,92 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_DISCO_INFO', 'http://jabber.org/protocol/disco#info'); +define('NS_DISCO_ITEMS', 'http://jabber.org/protocol/disco#items'); + +class XEP_0030 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array( + + ); + } + + // + // api methods + // + + public function get_info_pkt($entity_jid) { + return $this->jaxl->get_iq_pkt( + array('type'=>'get', 'from'=>$this->jaxl->full_jid->to_string(), 'to'=>$entity_jid), + new JAXLXml('query', NS_DISCO_INFO) + ); + } + + public function get_info($entity_jid, $callback=null) { + $pkt = $this->get_info_pkt($entity_jid); + if($callback) $this->jaxl->add_cb('on_stanza_id_'.$pkt->id, $callback); + $this->jaxl->send($pkt); + } + + public function get_items_pkt($entity_jid) { + return $this->jaxl->get_iq_pkt( + array('type'=>'get', 'from'=>$this->jaxl->full_jid->to_string(), 'to'=>$entity_jid), + new JAXLXml('query', NS_DISCO_ITEMS) + ); + } + + public function get_items($entity_jid, $callback=null) { + $pkt = $this->get_items_pkt($entity_jid); + if($callback) $this->jaxl->add_cb('on_stanza_id_'.$pkt->id, $callback); + $this->jaxl->send($pkt); + } + + // + // event callbacks + // + +} + +?> Index: externals/JAXL/xep/xep_0045.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0045.php @@ -0,0 +1,114 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_MUC', 'http://jabber.org/protocol/muc'); + +class XEP_0045 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array(); + } + + public function send_groupchat($room_jid, $body, $thread=null, $subject=null) { + $msg = new XMPPMsg( + array( + 'type'=>'groupchat', + 'to'=>(($room_jid instanceof XMPPJid) ? $room_jid->to_string() : $room_jid), + 'from'=>$this->jaxl->full_jid->to_string() + ), + $body, + $thread, + $subject + ); + $this->jaxl->send($msg); + } + + // + // api methods (occupant use case) + // + + // room_full_jid simply means room jid with nick name as resource + public function get_join_room_pkt($room_full_jid, $options) { + $pkt = $this->jaxl->get_pres_pkt( + array( + 'from'=>$this->jaxl->full_jid->to_string(), + 'to'=>(($room_full_jid instanceof XMPPJid) ? $room_full_jid->to_string() : $room_full_jid) + ) + ); + $x = $pkt->c('x', NS_MUC); + if (isset($options['no_history'])) { + $x->c('history')->attrs(array('maxstanzas' => 0, 'seconds' => 0)); + } + return $x; + } + + public function join_room($room_full_jid, $options = array()) { + $pkt = $this->get_join_room_pkt($room_full_jid, $options); + $this->jaxl->send($pkt); + } + + public function get_leave_room_pkt($room_full_jid) { + return $this->jaxl->get_pres_pkt( + array('type'=>'unavailable', 'from'=>$this->jaxl->full_jid->to_string(), 'to'=>(($room_full_jid instanceof XMPPJid) ? $room_full_jid->to_string() : $room_full_jid)) + ); + } + + public function leave_room($room_full_jid) { + $pkt = $this->get_leave_room_pkt($room_full_jid); + $this->jaxl->send($pkt); + } + + // + // api methods (moderator use case) + // + + + + // + // event callbacks + // + +} + +?> Index: externals/JAXL/xep/xep_0060.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0060.php @@ -0,0 +1,139 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_PUBSUB', 'http://jabber.org/protocol/pubsub'); + +class XEP_0060 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array(); + } + + // + // api methods (entity use case) + // + + // + // api methods (subscriber use case) + // + + public function get_subscribe_pkt($service, $node, $jid=null) { + $child = new JAXLXml('pubsub', NS_PUBSUB); + $child->c('subscribe', null, array('node'=>$node, 'jid'=>($jid ? $jid : $this->jaxl->full_jid->to_string()))); + return $this->get_iq_pkt($service, $child); + } + + public function subscribe($service, $node, $jid=null) { + $this->jaxl->send($this->get_subscribe_pkt($service, $node, $jid)); + } + + public function unsubscribe() { + + } + + public function get_subscription_options() { + + } + + public function set_subscription_options() { + + } + + public function get_node_items() { + + } + + // + // api methods (publisher use case) + // + + public function get_publish_item_pkt($service, $node, $item) { + $child = new JAXLXml('pubsub', NS_PUBSUB); + $child->c('publish', null, array('node'=>$node)); + $child->cnode($item); + return $this->get_iq_pkt($service, $child); + } + + public function publish_item($service, $node, $item) { + $this->jaxl->send($this->get_publish_item_pkt($service, $node, $item)); + } + + public function delete_item() { + + } + + // + // api methods (owner use case) + // + + public function get_create_node_pkt($service, $node) { + $child = new JAXLXml('pubsub', NS_PUBSUB); + $child->c('create', null, array('node'=>$node)); + return $this->get_iq_pkt($service, $child); + } + + public function create_node($service, $node) { + $this->jaxl->send($this->get_create_node_pkt($service, $node)); + } + + // + // event callbacks + // + + + // + // local methods + // + + // this always add attrs + protected function get_iq_pkt($service, $child, $type='set') { + return $this->jaxl->get_iq_pkt( + array('type'=>$type, 'from'=>$this->jaxl->full_jid->to_string(), 'to'=>$service), + $child + ); + } + +} + +?> Index: externals/JAXL/xep/xep_0077.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0077.php @@ -0,0 +1,83 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_FEATURE_REGISTER', 'http://jabber.org/features/iq-register'); +define('NS_INBAND_REGISTER', 'jabber:iq:register'); + +class XEP_0077 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array( + + ); + } + + // + // api methods + // + + public function get_form_pkt($domain) { + return $this->jaxl->get_iq_pkt( + array('to'=>$domain, 'type'=>'get'), + new JAXLXml('query', NS_INBAND_REGISTER) + ); + } + + public function get_form($domain) { + $this->jaxl->send($this->get_form_pkt($domain)); + } + + public function set_form($domain, $form) { + $query = new JAXLXml('query', NS_INBAND_REGISTER); + foreach($form as $k=>$v) $query->c($k, null, array(), $v)->up(); + $pkt = $this->jaxl->get_iq_pkt( + array('to'=>$domain, 'type'=>'set'), + $query + ); + $this->jaxl->send($pkt); + } + +} + +?> Index: externals/JAXL/xep/xep_0114.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0114.php @@ -0,0 +1,95 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_JABBER_COMPONENT_ACCEPT', 'jabber:component:accept'); + +class XEP_0114 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array( + 'on_connect' => 'start_stream', + 'on_stream_start' => 'start_handshake', + 'on_handshake_stanza' => 'logged_in', + 'on_error_stanza' => 'logged_out' + ); + } + + // + // event callbacks + // + + public function start_stream() { + $xml = ''; + $this->jaxl->send_raw($xml); + } + + public function start_handshake($stanza) { + _debug("starting component handshake"); + $id = $stanza->id; + $hash = strtolower(sha1($id.$this->jaxl->pass)); + $stanza = new JAXLXml('handshake', null, $hash); + $this->jaxl->send($stanza); + } + + public function logged_in($stanza) { + _debug("component handshake complete"); + $this->jaxl->handle_auth_success(); + return array("logged_in", 1); + } + + public function logged_out($stanza) { + if($stanza->name == "error" && $stanza->ns == NS_XMPP) { + $reason = $stanza->childrens[0]->name; + $this->jaxl->handle_auth_failure($reason); + $this->jaxl->send_end_stream(); + return array("logged_out", 0); + } + else { + _debug("uncatched stanza received in logged_out"); + } + } + +} + +?> Index: externals/JAXL/xep/xep_0115.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0115.php @@ -0,0 +1,73 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_CAPS', 'http://jabber.org/protocol/caps'); + +class XEP_0115 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array(); + } + + // + // api methods + // + + public function get_caps_pkt($cat, $type, $lang, $name, $node, $features) { + asort($features); + $S = $cat.'/'.$type.'/'.$lang.'/'.$name.'<'; + foreach($features as $feature) $S .= $feature.'<'; + $ver = base64_encode(sha1($S, true)); + + $stanza = new JAXLXml('c', NS_CAPS, array('hash'=>'sha1', 'node'=>$node, 'ver'=>$ver)); + return $stanza; + } + + // + // event callbacks + // + +} + +?> Index: externals/JAXL/xep/xep_0199.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0199.php @@ -0,0 +1,60 @@ + 'on_auth_success', + 'on_get_iq' => 'on_xmpp_ping' + ); + } + + // + // api methods + // + + public function get_ping_pkt() { + $attrs = array( + 'type'=>'get', + 'from'=>$this->jaxl->full_jid->to_string(), + 'to'=>$this->jaxl->full_jid->domain + ); + + return $this->jaxl->get_iq_pkt( + $attrs, + new JAXLXml('ping', NS_XMPP_PING) + ); + } + + public function ping() { + $this->jaxl->send($this->get_ping_pkt()); + } + + // + // event callbacks + // + + public function on_auth_success() { + JAXLLoop::$clock->call_fun_periodic(30 * pow(10,6), array(&$this, 'ping')); + } + + public function on_xmpp_ping($stanza) { + if($stanza->exists('ping', NS_XMPP_PING)) { + $stanza->type = "result"; + $stanza->to = $stanza->from; + $stanza->from = $this->jaxl->full_jid->to_string(); + $this->jaxl->send($stanza); + } + } + +} + +?> Index: externals/JAXL/xep/xep_0203.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0203.php @@ -0,0 +1,63 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_DELAYED_DELIVERY', 'urn:xmpp:delay'); + +class XEP_0203 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array(); + } + + // + // api methods + // + + // + // event callbacks + // + +} + +?> Index: externals/JAXL/xep/xep_0206.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0206.php @@ -0,0 +1,236 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_HTTP_BIND', 'http://jabber.org/protocol/httpbind'); +define('NS_BOSH', 'urn:xmpp:xbosh'); + +class XEP_0206 extends XMPPXep { + + private $mch = null; + public $chs = array(); + private $recv_cb = null; + + public $rid = null; + public $sid = null; + private $hold = 1; + private $wait = 30; + + private $restarted = false; + + public $headers = array( + 'Accept-Encoding: gzip, deflate', + 'Content-Type: text/xml; charset=utf-8' + ); + + // + // abstract method + // + + public function init() { + $this->mch = curl_multi_init(); + + return array( + + ); + } + + // + // event callbacks + // + + public function send($body) { + if(is_object($body)) { + $body = $body->to_string(); + } + else { + if(substr($body, 0, 15) == 'restarted = true; + + $body = new JAXLXml('body', NS_HTTP_BIND, array( + 'sid' => $this->sid, + 'rid' => ++$this->rid, + 'to' => @$this->jaxl->jid ? $this->jaxl->jid->domain : $this->jaxl->cfg['domain'], + 'xmpp:restart' => 'true', + 'xmlns:xmpp' => NS_BOSH + )); + + $body = $body->to_string(); + } + else if(substr($body, 0, 16) == '') { + $body = new JAXLXml('body', NS_HTTP_BIND, array( + 'sid' => $this->sid, + 'rid' => ++$this->rid, + 'type' => 'terminate' + )); + + $body = $body->to_string(); + } + else { + $body = $this->wrap($body); + } + } + _debug("posting to ".$this->jaxl->cfg['bosh_url']." body ".$body); + + $this->chs[$this->rid] = curl_init($this->jaxl->cfg['bosh_url']); + curl_setopt($this->chs[$this->rid], CURLOPT_RETURNTRANSFER, true); + curl_setopt($this->chs[$this->rid], CURLOPT_ENCODING, 'gzip,deflate'); + curl_setopt($this->chs[$this->rid], CURLOPT_HTTPHEADER, $this->headers); + curl_setopt($this->chs[$this->rid], CURLOPT_FOLLOWLOCATION, true); + curl_setopt($this->chs[$this->rid], CURLOPT_VERBOSE, false); + curl_setopt($this->chs[$this->rid], CURLOPT_POST, 1); + curl_setopt($this->chs[$this->rid], CURLOPT_POSTFIELDS, $body); + + curl_multi_add_handle($this->mch, $this->chs[$this->rid]); + } + + public function recv() { + if($this->restarted) { + $this->restarted = false; + + // fool xmpp_stream state machine with stream start packet + // and make transition to wait_for_stream_features state + if($this->recv_cb) call_user_func($this->recv_cb, $this->jaxl->get_start_stream(new XMPPJid("bosh.jaxl"))); + } + + _debug("recving for $this->rid"); + do { + $ret = curl_multi_exec($this->mch, $running); + $changed = curl_multi_select($this->mch, 0.1); + + if($changed == 0 && $running == 0) { + $ch = @$this->chs[$this->rid]; + if($ch) { + $data = curl_multi_getcontent($ch); + + curl_multi_remove_handle($this->mch, $ch); + unset($this->chs[$this->rid]); + _debug("recvd for $this->rid ".$data); + + list($body, $stanza) = $this->unwrap($data); + $body = new SimpleXMLElement($body); + $attrs = $body->attributes(); + + if(@$attrs['type'] == 'terminate') { + // fool me again + if($this->recv_cb) call_user_func($this->recv_cb, $this->jaxl->get_end_stream()); + } + else { + if(!$this->sid) { + $this->sid = $attrs['sid']; + } + + if($this->recv_cb) call_user_func($this->recv_cb, $stanza); + } + } + else { + _error("no ch found"); + exit; + } + } + } while($running); + } + + public function set_callback($recv_cb) { + $this->recv_cb = $recv_cb; + } + + public function wrap($stanza) { + return ''.$stanza.''; + } + + public function unwrap($body) { + // a dirty way but it works efficiently + if(substr($body, -2, 2) == "/>") preg_match_all('//smi', $body, $m); + else preg_match_all('/(.*)<\/body>/smi', $body, $m); + + if(isset($m[1][0])) $envelop = ""; + else $envelop = ""; + + if(isset($m[2][0])) $payload = $m[2][0]; + else $payload = ''; + + return array($envelop, $payload); + } + + public function session_start() { + $this->rid = @$this->jaxl->cfg['bosh_rid'] ? $this->jaxl->cfg['bosh_rid'] : rand(1000, 10000); + $this->hold = @$this->jaxl->cfg['bosh_hold'] ? $this->jaxl->cfg['bosh_hold'] : $this->hold; + $this->wait = @$this->jaxl->cfg['bosh_wait'] ? $this->jaxl->cfg['bosh_wait'] : $this->wait; + + // fool xmpp_stream state machine with stream start packet + // and make transition to wait_for_stream_features state + if($this->recv_cb) + call_user_func($this->recv_cb, $this->jaxl->get_start_stream(new XMPPJid("bosh.jaxl"))); + + $attrs = array( + 'content' => 'text/xml; charset=utf-8', + 'to' => @$this->jaxl->jid ? $this->jaxl->jid->domain : $this->jaxl->cfg['domain'], + 'route' => 'xmpp:'.$this->jaxl->cfg['host'].':'.$this->jaxl->cfg['port'], + 'secure' => 'true', + 'xml:lang' => 'en', + 'xmpp:version' => '1.0', + 'xmlns:xmpp' => NS_BOSH, + 'hold' => $this->hold, + 'wait' => $this->wait, + 'rid' => $this->rid, + 'ver' => '1.10' + ); + + if(@$this->jaxl->cfg['jid']) $attrs['from'] = @$this->jaxl->cfg['jid']; + $body = new JAXLXml('body', NS_HTTP_BIND, $attrs); + $this->send($body); + } + + public function ping() { + $body = new JAXLXml('body', NS_HTTP_BIND, array('sid' => $this->sid, 'rid' => ++$this->rid)); + $this->send($body); + } + + public function session_end() { + $this->disconnect(); + } + + public function disconnect() { + _debug("disconnecting"); + } + +} + +?> Index: externals/JAXL/xep/xep_0249.php =================================================================== --- /dev/null +++ externals/JAXL/xep/xep_0249.php @@ -0,0 +1,81 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_xep.php'; + +define('NS_DIRECT_MUC_INVITATION', 'jabber:x:conference'); + +class XEP_0249 extends XMPPXep { + + // + // abstract method + // + + public function init() { + return array(); + } + + // + // api methods + // + + public function get_invite_pkt($to_bare_jid, $room_jid, $password=null, $reason=null, $thread=null, $continue=null) { + $xattrs = array('jid'=>$room_jid); + if($password) $xattrs['password'] = $password; + if($reason) $xattrs['reason'] = $reason; + if($thread) $xattrs['thread'] = $thread; + if($continue) $xattrs['continue'] = $continue; + + return $this->jaxl->get_msg_pkt( + array('from'=>$this->jaxl->full_jid->to_string(), 'to'=>$to_bare_jid), + null, null, null, + new JAXLXml('x', NS_DIRECT_MUC_INVITATION, $xattrs) + ); + } + + public function invite($to_bare_jid, $room_jid, $password=null, $reason=null, $thread=null, $continue=null) { + $this->jaxl->send($this->get_invite_pkt($to_bare_jid, $room_jid, $password, $reason, $thread, $continue)); + } + + // + // event callbacks + // + +} + +?> Index: externals/JAXL/xmpp/README.md =================================================================== --- /dev/null +++ externals/JAXL/xmpp/README.md @@ -0,0 +1,12 @@ +Jaxl XMPP Stack: +---------------- +XMPP Stack implementation includes: + +* XMPPStream - RFC 6120 and RFC 6121 +* XMPPXep - Abstract XMPP Extension class +* XMPPStanza - Generic Stanza object +* XMPPPres - Generic Presence object +* XMPPMsg - Generic Message object +* XMPPIq - Generic IQ object +* XMPPJid - JabberId object +* XMPPRosterItem - A XMPP Roster Item representation \ No newline at end of file Index: externals/JAXL/xmpp/xmpp_iq.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_iq.php @@ -0,0 +1,49 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_stanza.php'; + +class XMPPIq extends XMPPStanza { + + public function __construct($attrs) { + parent::__construct('iq', $attrs); + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_jid.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_jid.php @@ -0,0 +1,83 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +/** + * + * Xmpp Jid + * + * @author abhinavsingh + * + */ +class XMPPJid { + + public $node = null; + public $domain = null; + public $resource = null; + public $bare = null; + + public function __construct($str) { + $tmp = explode("@", $str); + if(sizeof($tmp) == 2) { + $this->node = $tmp[0]; + $tmp = explode("/", $tmp[1]); + if(sizeof($tmp) == 2) { + $this->domain = $tmp[0]; + $this->resource = $tmp[1]; + } + else { + $this->domain = $tmp[0]; + } + } + else if(sizeof($tmp) == 1) { + $this->domain = $tmp[0]; + } + + $this->bare = $this->node ? $this->node."@".$this->domain : $this->domain; + } + + public function to_string() { + $str = ""; + if($this->node) $str .= $this->node.'@'.$this->domain; + else if($this->domain) $str .= $this->domain; + if($this->resource) $str .= '/'.$this->resource; + return $str; + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_msg.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_msg.php @@ -0,0 +1,53 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_stanza.php'; + +class XMPPMsg extends XMPPStanza { + + public function __construct($attrs, $body=null, $thread=null, $subject=null) { + parent::__construct('message', $attrs); + + if($body) $this->c('body')->t($body)->up(); + if($thread) $this->c('thread')->t($thread)->up(); + if($subject) $this->c('subject')->t($subject)->up(); + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_nss.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_nss.php @@ -0,0 +1,62 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +// XML +define('NS_XML_pfx', "xml"); +define('NS_XML', 'http://www.w3.org/XML/1998/namespace'); + +// XMPP Core (RFC 3920) +define('NS_XMPP_pfx', "stream"); +define('NS_XMPP', 'http://etherx.jabber.org/streams'); +define('NS_STREAM_ERRORS', 'urn:ietf:params:xml:ns:xmpp-streams'); +define('NS_TLS', 'urn:ietf:params:xml:ns:xmpp-tls'); +define('NS_SASL', 'urn:ietf:params:xml:ns:xmpp-sasl'); +define('NS_BIND', 'urn:ietf:params:xml:ns:xmpp-bind'); +define('NS_STANZA_ERRORS', 'urn:ietf:params:xml:ns:xmpp-stanzas'); + +// XMPP-IM (RFC 3921) +define('NS_JABBER_CLIENT', 'jabber:client'); +define('NS_JABBER_SERVER', 'jabber:server'); +define('NS_SESSION', 'urn:ietf:params:xml:ns:xmpp-session'); +define('NS_ROSTER', 'jabber:iq:roster'); + +// Stream Compression (XEP-0138) +define('NS_COMPRESSION_FEATURE', 'http://jabber.org/features/compress'); +define('NS_COMPRESSION_PROTOCOL', 'http://jabber.org/protocol/compress'); + +?> Index: externals/JAXL/xmpp/xmpp_pres.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_pres.php @@ -0,0 +1,53 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_stanza.php'; + +class XMPPPres extends XMPPStanza { + + public function __construct($attrs, $status=null, $show=null, $priority=null) { + parent::__construct('presence', $attrs); + + if($status) $this->c('status')->t($status)->up(); + if($show) $this->c('show')->t($show)->up(); + if($priority) $this->c('priority')->t($priority)->up(); + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_roster_item.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_roster_item.php @@ -0,0 +1,59 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/** + * + * @author abhinavsingh + */ +class XMPPRosterItem { + + public $jid = null; + public $subscription = null; + public $groups = array(); + public $resources = array(); + public $vcard = null; + + public function __construct($jid, $subscription, $groups) { + $this->jid = $jid; + $this->subscription = $subscription; + $this->groups = $groups; + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_stanza.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_stanza.php @@ -0,0 +1,176 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +require_once JAXL_CWD.'/xmpp/xmpp_nss.php'; +require_once JAXL_CWD.'/xmpp/xmpp_jid.php'; +require_once JAXL_CWD.'/core/jaxl_xml.php'; + +/** + * Generic xmpp stanza object which provide convinient access pattern over xml objects + * Also to be able to convert an existing xml object into stanza object (to get access patterns going) + * this class doesn't extend xml, but infact works on a reference of xml object + * If not provided during constructor, new xml object is created and saved as reference + * + * @author abhinavsingh + * + */ +class XMPPStanza { + + private $xml; + + public function __construct($name, $attrs=array(), $ns=NS_JABBER_CLIENT) { + if($name instanceof JAXLXml) $this->xml = $name; + else $this->xml = new JAXLXml($name, $ns, $attrs); + } + + public function __call($method, $args) { + return call_user_func_array(array($this->xml, $method), $args); + } + + public function __get($prop) { + switch($prop) { + // access to jaxl xml properties + case 'name': + case 'ns': + case 'text': + case 'attrs': + case 'childrens': + return $this->xml->$prop; + break; + + // access to common xml attributes + case 'to': + case 'from': + case 'id': + case 'type': + return @$this->xml->attrs[$prop] ? $this->xml->attrs[$prop] : null; + break; + + // access to parts of common xml attributes + case 'to_node': + case 'to_domain': + case 'to_resource': + case 'from_node': + case 'from_domain': + case 'from_resource': + list($attr, $key) = explode('_', $prop); + $val = @$this->xml->attrs[$attr] ? $this->xml->attrs[$attr] : null; + if(!$val) return null; + + $val = new XMPPJid($val); + return $val->$key; + break; + + // access to first child element text + case 'status': + case 'show': + case 'priority': + case 'body': + case 'thread': + case 'subject': + $val = $this->xml->exists($prop); + if(!$val) return null; + return $val->text; + break; + + default: + return null; + break; + } + } + + public function __set($prop, $val) { + switch($prop) { + // access to jaxl xml properties + case 'name': + case 'ns': + case 'text': + case 'attrs': + case 'childrens': + return $this->xml->$prop = $val; + break; + + // access to common xml attributes + case 'to': + case 'from': + case 'id': + case 'type': + $this->xml->attrs[$prop] = $val; + return true; + break; + + // access to parts of common xml attributes + case 'to_node': + case 'to_domain': + case 'to_resource': + case 'from_node': + case 'from_domain': + case 'from_resource': + list($attr, $key) = explode('_', $prop); + $val1 = @$this->xml->attrs[$attr]; + if(!$val1) $val1 = ''; + + $val1 = new XMPPJid($val1); + $val1->$key = $val; + + $this->xml->attrs[$attr] = $val1->to_string(); + return true; + break; + + // access to first child element text + case 'status': + case 'show': + case 'priority': + case 'body': + case 'thread': + case 'subject': + $val1 = $this->xml->exists($prop); + if(!$val1) $this->xml->c($prop)->t($val)->up(); + else $this->xml->update($prop, $val1->ns, $val1->attrs, $val); + return true; + break; + + default: + return null; + break; + } + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_stream.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_stream.php @@ -0,0 +1,671 @@ +. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the name of Abhinav Singh nor the names of his +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +require_once JAXL_CWD.'/core/jaxl_fsm.php'; +require_once JAXL_CWD.'/core/jaxl_xml.php'; +require_once JAXL_CWD.'/core/jaxl_xml_stream.php'; +require_once JAXL_CWD.'/core/jaxl_util.php'; +require_once JAXL_CWD.'/core/jaxl_socket_client.php'; + +require_once JAXL_CWD.'/xmpp/xmpp_nss.php'; +require_once JAXL_CWD.'/xmpp/xmpp_jid.php'; +require_once JAXL_CWD.'/xmpp/xmpp_msg.php'; +require_once JAXL_CWD.'/xmpp/xmpp_pres.php'; +require_once JAXL_CWD.'/xmpp/xmpp_iq.php'; + +/** + * + * Enter description here ... + * @author abhinavsingh + * + */ +abstract class XMPPStream extends JAXLFsm { + + // jid with binding resource value + public $full_jid = null; + + // input parameters + public $jid = null; + public $pass = null; + public $resource = null; + public $force_tls = false; + + // underlying socket/bosh and xml stream ref + protected $trans = null; + protected $xml = null; + + // stanza id + protected $last_id = 0; + + // + // abstract methods + // + + abstract public function handle_stream_start($stanza); + abstract public function handle_auth_mechs($stanza, $mechs); + abstract public function handle_auth_success(); + abstract public function handle_auth_failure($reason); + abstract public function handle_iq($stanza); + abstract public function handle_presence($stanza); + abstract public function handle_message($stanza); + abstract public function handle_other($event, $args); + + // + // public api + // + + public function __construct($transport, $jid, $pass=null, $resource=null, $force_tls=false) { + $this->jid = $jid; + $this->pass = $pass; + $this->resource = $resource ? $resource : md5(time()); + $this->force_tls = $force_tls; + + $this->trans = $transport; + $this->xml = new JAXLXmlStream(); + + $this->trans->set_callback(array(&$this->xml, "parse")); + $this->xml->set_callback(array(&$this, "start_cb"), array(&$this, "end_cb"), array(&$this, "stanza_cb")); + + parent::__construct("setup"); + } + + public function __destruct() { + //_debug("cleaning up xmpp stream..."); + } + + public function handle_invalid_state($r) { + _error("got invalid return value from state handler '".$this->state."', sending end stream..."); + $this->send_end_stream(); + $this->state = "logged_out"; + _notice("state handler '".$this->state."' returned ".serialize($r).", kindly report this to developers"); + } + + public function send($stanza) { + $this->trans->send($stanza->to_string()); + } + + public function send_raw($data) { + $this->trans->send($data); + } + + // + // pkt creation utilities + // + + public function get_start_stream($jid) { + $xml = 'bare)) $xml .= 'from="'.$jid->bare.'" '; + if(isset($jid->domain)) $xml .= 'to="'.$jid->domain.'" '; + $xml .= 'xmlns="'.NS_JABBER_CLIENT.'" xml:lang="en" xmlns:xml="'.NS_XML.'">'; + return $xml; + } + + public function get_end_stream() { + return ''; + } + + public function get_starttls_pkt() { + $stanza = new JAXLXml('starttls', NS_TLS); + return $stanza; + } + + public function get_compress_pkt($method) { + $stanza = new JAXLXml('compress', NS_COMPRESSION_PROTOCOL); + $stanza->c('method')->t($method); + return $stanza; + } + + // someday this all needs to go inside jaxl_sasl_auth + public function get_auth_pkt($mechanism, $user, $pass) { + $stanza = new JAXLXml('auth', NS_SASL, array('mechanism'=>$mechanism)); + + switch($mechanism) { + case 'PLAIN': + case 'X-OAUTH2': + $stanza->t(base64_encode("\x00".$user."\x00".$pass)); + break; + case 'DIGEST-MD5': + break; + case 'CRAM-MD5': + break; + case 'SCRAM-SHA-1': + // client first message always starts with n, y or p for GS2 extensibility + $stanza->t(base64_encode("n,,n=".$user.",r=".JAXLUtil::get_nonce(false))); + break; + case 'ANONYMOUS': + break; + case 'EXTERNAL': + // If no password, then we are probably doing certificate auth, so follow RFC 6120 form and pass '='. + if(strlen($pass) == 0) + $stanza->t('='); + break; + default: + break; + } + + return $stanza; + } + + public function get_challenge_response_pkt($challenge) { + $stanza = new JAXLXml('response', NS_SASL); + $decoded = $this->explode_data(base64_decode($challenge)); + + if(!isset($decoded['rspauth'])) { + _debug("calculating response to challenge"); + $stanza->t($this->get_challenge_response($decoded)); + } + + return $stanza; + } + + public function get_challenge_response($decoded) { + $response = array(); + $nc = '00000001'; + + if(!isset($decoded['digest-uri'])) + $decoded['digest-uri'] = 'xmpp/'.$this->jid->domain; + + $decoded['cnonce'] = base64_encode(JAXLUtil::get_nonce()); + + if(isset($decoded['qop']) && $decoded['qop'] != 'auth' && strpos($decoded['qop'], 'auth') !== false) + $decoded['qop'] = 'auth'; + + $data = array_merge($decoded, array('nc'=>$nc)); + + $response = array( + 'username'=> $this->jid->node, + 'response' => $this->encrypt_password($data, $this->jid->node, $this->pass), + 'charset' => 'utf-8', + 'nc' => $nc, + 'qop' => 'auth' + ); + + foreach(array('nonce', 'digest-uri', 'realm', 'cnonce') as $key) + if(isset($decoded[$key])) + $response[$key] = $decoded[$key]; + + return base64_encode($this->implode_data($response)); + } + + public function get_bind_pkt($resource) { + $stanza = new JAXLXml('bind', NS_BIND); + $stanza->c('resource')->t($resource); + return $this->get_iq_pkt(array( + 'type' => 'set' + ), $stanza); + } + + public function get_session_pkt() { + $stanza = new JAXLXml('session', NS_SESSION); + return $this->get_iq_pkt(array( + 'type' => 'set' + ), $stanza); + } + + public function get_msg_pkt($attrs, $body=null, $thread=null, $subject=null, $payload=null) { + $msg = new XMPPMsg($attrs, $body, $thread, $subject); + if(!$msg->id) $msg->id = $this->get_id(); + if($payload) $msg->cnode($payload); + return $msg; + } + + public function get_pres_pkt($attrs, $status=null, $show=null, $priority=null, $payload=null) { + $pres = new XMPPPres($attrs, $status, $show, $priority); + if(!$pres->id) $pres->id = $this->get_id(); + if($payload) $pres->cnode($payload); + return $pres; + } + + public function get_iq_pkt($attrs, $payload) { + $iq = new XMPPIq($attrs); + if(!$iq->id) $iq->id = $this->get_id(); + if($payload) $iq->cnode($payload); + return $iq; + } + + public function get_id() { + ++$this->last_id; + return dechex($this->last_id); + } + + public function explode_data($data) { + $data = explode(',', $data); + $pairs = array(); + $key = false; + + foreach($data as $pair) { + $dd = strpos($pair, '='); + if($dd) { + $key = trim(substr($pair, 0, $dd)); + $pairs[$key] = trim(trim(substr($pair, $dd + 1)), '"'); + } + else if(strpos(strrev(trim($pair)), '"') === 0 && $key) { + $pairs[$key] .= ',' . trim(trim($pair), '"'); + continue; + } + } + + return $pairs; + } + + public function implode_data($data) { + $return = array(); + foreach($data as $key => $value) $return[] = $key . '="' . $value . '"'; + return implode(',', $return); + } + + public function encrypt_password($data, $user, $pass) { + foreach(array('realm', 'cnonce', 'digest-uri') as $key) + if(!isset($data[$key])) + $data[$key] = ''; + + $pack = md5($user.':'.$data['realm'].':'.$pass); + + if(isset($data['authzid'])) + $a1 = pack('H32',$pack).sprintf(':%s:%s:%s',$data['nonce'],$data['cnonce'],$data['authzid']); + else + $a1 = pack('H32',$pack).sprintf(':%s:%s',$data['nonce'],$data['cnonce']); + + $a2 = 'AUTHENTICATE:'.$data['digest-uri']; + return md5(sprintf('%s:%s:%s:%s:%s:%s', md5($a1), $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'], md5($a2))); + } + + // + // socket senders + // + + protected function send_start_stream($jid) { + $this->send_raw($this->get_start_stream($jid)); + } + + public function send_end_stream() { + $this->send_raw($this->get_end_stream()); + } + + protected function send_auth_pkt($type, $user, $pass) { + $this->send($this->get_auth_pkt($type, $user, $pass)); + } + + protected function send_starttls_pkt() { + $this->send($this->get_starttls_pkt()); + } + + protected function send_compress_pkt($method) { + $this->send($this->get_compress_pkt($method)); + } + + protected function send_challenge_response($challenge) { + $this->send($this->get_challenge_response_pkt($challenge)); + } + + protected function send_bind_pkt($resource) { + $this->send($this->get_bind_pkt($resource)); + } + + protected function send_session_pkt() { + $this->send($this->get_session_pkt()); + } + + private function do_connect($args) { + $socket_path = @$args[0]; + if($this->trans->connect($socket_path)) { + return array("connected", 1); + } + else { + return array("disconnected", 0); + } + } + + // + // fsm States + // + + public function setup($event, $args) { + switch($event) { + case "connect": + return $this->do_connect($args); + break; + // someone else already started the stream + // even before "connect" was called must be bosh + case "start_cb": + $stanza = $args[0]; + return $this->handle_stream_start($stanza); + break; + default: + _debug("uncatched $event"); + //print_r($args); + return $this->handle_other($event, $args); + //return array("setup", 0); + break; + } + } + + public function connected($event, $args) { + switch($event) { + case "start_stream": + $this->send_start_stream($this->jid); + return array("wait_for_stream_start", 1); + break; + // someone else already started the stream before us + // even before "start_stream" was called + // must be component + case "start_cb": + $stanza = $args[0]; + return $this->handle_stream_start($stanza); + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("connected", 0); + break; + } + } + + public function disconnected($event, $args) { + switch($event) { + case "connect": + return $this->do_connect($args); + break; + case "end_stream": + $this->send_end_stream(); + return "logged_out"; + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("disconnected", 0); + break; + } + } + + public function wait_for_stream_start($event, $args) { + switch($event) { + case "start_cb": + // TODO: save stream id and other meta info + //_debug("stream started"); + return "wait_for_stream_features"; + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_stream_start", 0); + break; + } + } + + // XEP-0170: Recommended Order of Stream Feature Negotiation + public function wait_for_stream_features($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + // get starttls requirements + $starttls = $stanza->exists('starttls', NS_TLS); + $required = $starttls ? ($this->force_tls ? true : ($starttls->exists('required') ? true : false)) : false; + + if($starttls && $required) { + $this->send_starttls_pkt(); + return "wait_for_tls_result"; + } + + // handle auth mech + $mechs = $stanza->exists('mechanisms', NS_SASL); + if($mechs) { + $new_state = $this->handle_auth_mechs($stanza, $mechs); + return $new_state ? $new_state : "wait_for_sasl_response"; + } + + // post auth + $bind = $stanza->exists('bind', NS_BIND) ? true : false; + $sess = $stanza->exists('session', NS_SESSION) ? true : false; + $comp = $stanza->exists('compression', NS_COMPRESSION_FEATURE) ? true : false; + + if($bind) { + $this->send_bind_pkt($this->resource); + return "wait_for_bind_response"; + } + /*// compression not supported due to bug in php stream filters + else if($comp) { + $this->send_compress_pkt("zlib"); + return "wait_for_compression_result"; + }*/ + else { + _debug("no catch"); + } + + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_stream_features", 0); + break; + } + } + + public function wait_for_tls_result($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + if($stanza->name == 'proceed' && $stanza->ns == NS_TLS) { + if($this->trans->crypt()) { + $this->xml->reset_parser(); + $this->send_start_stream($this->jid); + return "wait_for_stream_start"; + } + else { + $this->handle_auth_failure("tls-negotiation-failed"); + return "logged_out"; + } + } + else { + // FIXME: here + } + + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_tls_result", 0); + break; + } + } + + public function wait_for_compression_result($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + if($stanza->name == 'compressed' && $stanza->ns == NS_COMPRESSION_PROTOCOL) { + $this->xml->reset_parser(); + $this->trans->compress(); + $this->send_start_stream($this->jid); + return "wait_for_stream_start"; + } + + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_compression_result", 0); + break; + } + } + + public function wait_for_sasl_response($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + if($stanza->name == 'failure' && $stanza->ns == NS_SASL) { + $reason = $stanza->childrens[0]->name; + //_debug("sasl failed with reason ".$reason.""); + $this->handle_auth_failure($reason); + return "logged_out"; + } + else if($stanza->name == 'challenge' && $stanza->ns == NS_SASL) { + $challenge = $stanza->text; + $this->send_challenge_response($challenge); + return "wait_for_sasl_response"; + } + else if($stanza->name == 'success' && $stanza->ns == NS_SASL) { + $this->xml->reset_parser(); + $this->send_start_stream(@$this->jid); + return "wait_for_stream_start"; + } + else { + _debug("got unhandled sasl response"); + } + + return "wait_for_sasl_response"; + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_sasl_response", 0); + break; + } + } + + public function wait_for_bind_response($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + // TODO: chk on id + if($stanza->name == 'iq' && $stanza->attrs['type'] == 'result' + && ($jid = $stanza->exists('bind', NS_BIND)->exists('jid'))) { + $this->full_jid = new XMPPJid($jid->text); + $this->send_session_pkt(); + return "wait_for_session_response"; + } + else { + // FIXME: + } + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_bind_response", 0); + break; + } + } + + public function wait_for_session_response($event, $args) { + switch($event) { + case "stanza_cb": + $this->handle_auth_success(); + return "logged_in"; + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("wait_for_session_response", 0); + break; + } + } + + public function logged_in($event, $args) { + switch($event) { + case "stanza_cb": + $stanza = $args[0]; + + // call abstract + if($stanza->name == 'message') { + $this->handle_message($stanza); + } + else if($stanza->name == 'presence') { + $this->handle_presence($stanza); + } + else if($stanza->name == 'iq') { + $this->handle_iq($stanza); + } + else { + $this->handle_other($event, $args); + } + + return "logged_in"; + break; + case "end_cb": + $this->send_end_stream(); + return "logged_out"; + break; + case "end_stream": + $this->send_end_stream(); + return "logged_out"; + break; + case "disconnect": + $this->trans->disconnect(); + return "disconnected"; + break; + default: + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("logged_in", 0); + break; + } + } + + public function logged_out($event, $args) { + switch($event) { + case "end_cb": + $this->trans->disconnect(); + return "disconnected"; + break; + case "end_stream": + return "disconnected"; + break; + case "disconnect": + $this->trans->disconnect(); + return "disconnected"; + break; + case "connect": + return $this->do_connect($args); + break; + default: + // exit for any other event in logged_out state + _debug("uncatched $event"); + return $this->handle_other($event, $args); + //return array("logged_out", 0); + break; + } + } + +} + +?> Index: externals/JAXL/xmpp/xmpp_xep.php =================================================================== --- /dev/null +++ externals/JAXL/xmpp/xmpp_xep.php @@ -0,0 +1,66 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Abhinav Singh nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/** + * + * @author abhinavsingh + * + */ +abstract class XMPPXep { + + // init() method defines various callbacks + // required by this xep extension + abstract public function init(); + //abstract public $description; + //abstract public $dependencies; + + // reference to jaxl instance + // which required me + protected $jaxl = null; + + public function __construct($jaxl) { + $this->jaxl = $jaxl; + } + + public function __destruct() { + + } + +} + +?> Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -1039,6 +1039,7 @@ 'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php', 'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php', 'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php', + 'PhabricatorJabberProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorJabberProtocolAdapter.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', @@ -2774,6 +2775,7 @@ 'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface', 'PhabricatorInlineCommentPreviewController' => 'PhabricatorController', 'PhabricatorInlineSummaryView' => 'AphrontView', + 'PhabricatorJabberProtocolAdapter' => 'PhabricatorBaseProtocolAdapter', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorLDAPConfigOptions' => 'PhabricatorApplicationConfigOptions', Index: src/infrastructure/daemon/bot/adapter/PhabricatorJabberProtocolAdapter.php =================================================================== --- /dev/null +++ src/infrastructure/daemon/bot/adapter/PhabricatorJabberProtocolAdapter.php @@ -0,0 +1,94 @@ +getConfig('server'); + } + + // Hash map of command translations + public static $commandTranslations = array( + 'PRIVMSG' => 'MESSAGE'); + + public function connect() { + $server = $this->getConfig('server'); + $port = $this->getConfig('port', 5222); + $pass = $this->getConfig('pass'); + $user = $this->getConfig('user'); + + $this->muc_host = $this->getConfig('muc_domain', $server); + $this->nick = $this->getConfig('nick', $user); + + $this->messages = array(); + + $this->conn = new JAXL(array('jid' => "$user@$server", 'pass' => $pass, 'port' => $port, 'priv_dir' => '/tmp/.jaxl')); + $this->conn->require_xep(array('0045', '0199')); // 0045 is xep for MUC and 0199 is for ping + + $this->conn->add_cb('on_auth_success', array($this, 'onAuthSuccess')); + $this->conn->add_cb('on_groupchat_message', array($this, 'onGroupMessage')); + $this->conn->connect($this->conn->get_socket_path()); + $this->conn->start_stream(); + JAXLLoop::$clock = new JAXLClock(); + } + + public function onAuthSuccess() { + $this->conn->set_status(''); + + foreach ($this->getConfig('join') as $room) { + $this->conn->xeps['0045']->join_room($room.'@'.$this->muc_host.'/'.$this->nick, array('no_history' => true)); + } + } + + public function onGroupMessage($stanza) { + if (!$stanza->exists('body')) { + return; + } + + $senderJid = new XMPPJid($stanza->from); + + $sender = id(new PhabricatorBotUser())->setName($senderJid->resource); + $target = id(new PhabricatorBotChannel())->setName($senderJid->node.'@'.$senderJid->domain); + + $this->messages[] = id(new PhabricatorBotMessage()) + ->setCommand("MESSAGE") + ->setSender($sender) + ->setTarget($target) + ->setBody($stanza->body); + } + + public function getNextMessages($poll_frequency) { + JAXLLoop::$secs = $poll_frequency; + JAXLLoop::$usecs = 0; + + JAXLLoop::select(); + + $messages = $this->messages; + $this->messages = array(); + + return $messages; + } + + public function writeMessage(PhabricatorBotMessage $message) { + switch ($message->getCommand()) { + case 'MESSAGE': + case 'PASTE': + $name = $message->getTarget()->getName(); + $body = $message->getBody(); + $this->conn->xeps['0045']->send_groupchat($name, $body); + return true; + default: + return false; + } + } + + public function __destruct() { + $this->conn->disconnect(); + } +}