Guest User

Untitled

a guest
Sep 11th, 2012
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 14.28 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4. Copyright (c) 2011, NullWarez All rights reserved.
  5.  
  6. Redistribution and use in source and binary forms, with or without modification,
  7. are permitted provided that the following conditions are met:
  8.  
  9.  * Redistributions of source code must retain the above copyright notice,
  10.    this list of conditions and the following disclaimer.
  11.  
  12.  * Redistributions in binary form must reproduce the above copyright notice,
  13.    this list of conditions and the following disclaimer in the documentation
  14.    and/or other materials provided with the distribution.
  15.  
  16.  * The name of the author may not be used to endorse or promote products
  17.    derived from this software without specific prior written permission.
  18.  
  19. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  29. IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. POSSIBILITY OF SUCH DAMAGE.
  31. */
  32.  
  33. /**
  34. *
  35. * @package PHP DC++ Library (Non Threads)
  36. * @version 1.1.3a
  37. * @author NullWarez
  38. * @copyright Copyright (c) 2011, NullWarez
  39. * @license 3-clause BSD
  40. *
  41. */
  42.  
  43.  
  44. class PHPDClib
  45. {
  46.     private $handle_connection;
  47.     private $options = array(
  48.         'host'                => 'localhost',
  49.         'port'                => '411',
  50.         'bind_ip'             => '0.0.0.0',
  51.  
  52.         'nickname'            => 'PHPDClib',
  53.         'password'            => '',
  54.         'description'         => 'DC++ Library sf.net/projects/phpdclibrary',
  55.         'email'               => '',
  56.         'connection'          => 'LAN(T1)',
  57.         'tag'                 => '<PHPDCLib++ V:1.1.3a,M:P,H:1/0/0,S:10>',
  58.         'sharesize'           => '0',
  59.        
  60.         'userlist'            => 0,
  61.  
  62.         'debug'               => 0,
  63.         'frequency_low'       => 300000,
  64.         'frequency_high'      => 1000,
  65.         'read_buffer_size'    => 256000,
  66.  
  67.         'func_chat_public'    => 'chat_public',
  68.         'func_chat_private'   => 'chat_private',
  69.         'func_event_handler'  => 'event_handler'
  70.     );
  71.     private $control = array(
  72.         'connected'     => false
  73.     );
  74.    
  75.     public $hub_info = array(
  76.         'hubname'   => '',
  77.         'userlist' => array()
  78.     );
  79.  
  80.     private $curent_buffer = null;
  81.     private $read_buffer = null;
  82.     private $read_buffer_array = array();
  83.  
  84.     private $socket_tcp_recvspace = 0;
  85.  
  86.     private $frequency = 0;
  87.    
  88.     /**
  89.      * Main function to connect
  90.      *
  91.      * @access public
  92.      * @param array $optionArray
  93.      */
  94.     public function connect($optionArray)
  95.     {
  96.         $this->options = array_merge($this->options, $optionArray);
  97.         $this->reconnect();
  98.            
  99.         while(1)
  100.         {      
  101.             usleep($this->frequency);
  102.            
  103.             if($this->sock_error_trigger())
  104.             {
  105.                 $this->reconnect();
  106.                 continue;
  107.             }
  108.  
  109.             if($this->read_buffer_array || $this->read_buffer !== null)
  110.             {
  111.                 if($this->frequency != $this->options['frequency_high'])
  112.                     $this->frequency = $this->options['frequency_high'];
  113.             }
  114.             else
  115.             {
  116.                 if($this->frequency != $this->options['frequency_low'])
  117.                     $this->frequency = $this->options['frequency_low'];
  118.             }
  119.  
  120.             if($this->read_socket())
  121.                 continue;
  122.            
  123.             if(!$this->read_buffer_array)
  124.                 continue;
  125.                
  126.             $this->curent_buffer = array_shift($this->read_buffer_array);  
  127.             $this->_debug("RX: $this->curent_buffer");         
  128.             $temp_cmd = $this->get_cmd();
  129.            
  130.             do
  131.             {
  132.                 if('MyINFO' === $temp_cmd)
  133.                 {
  134.                         if(!$this->control['connected']) break;
  135.                         if(!$this->options['userlist']) break;
  136.  
  137.                         $str_pos = strpos($this->curent_buffer, 'L ');
  138.                         $tmp = substr($this->curent_buffer, $str_pos+2);
  139.                         $str_pos = strpos($tmp, ' ');
  140.                         $tmp = substr($tmp, 0, $str_pos);
  141.  
  142.                         $this->hub_info['userlist'][$tmp] = '';
  143.  
  144.                 }
  145.                 else if('$CHAT' === $temp_cmd)
  146.                 {
  147.                         if(!$this->control['connected']) break;
  148.  
  149.                         $msg_array = $this->get_public_message();
  150.  
  151.                         if($msg_array !== false)
  152.                             $this->options['func_chat_public']($msg_array[0], $msg_array[1], $this);
  153.                 }
  154.                 else if('Hello' === $temp_cmd) 
  155.                 {
  156.                         if($this->control['connected']) break;
  157.  
  158.                         $nickname = substr($this->curent_buffer, strpos($this->curent_buffer, ' ')+1);
  159.                         if($nickname != $this->options['nickname'])
  160.                         {
  161.                             $this->options['func_event_handler']('>BadNick', $this);
  162.                             break;
  163.                         }
  164.  
  165.                         $this->write_socket('$Version 1,0091');
  166.                         $this->write_socket('$MyINFO $ALL '.$this->options['nickname'].' '.$this->options['description'].$this->options['tag'].'$ $'.$this->options['connection'].'1$'.$this->options['email'].'$'.$this->options['sharesize'].'$');
  167.  
  168.                         if($this->options['userlist'])
  169.                             $this->write_socket('$GetNickList');
  170.  
  171.                         $this->control['connected'] = true;
  172.  
  173.                 }
  174.                 else if('Quit' === $temp_cmd)
  175.                 {
  176.                         if(!$this->control['connected']) break;
  177.                         if(!$this->options['userlist']) break;
  178.                        
  179.                         $tmp = substr($this->curent_buffer, 6);
  180.                        
  181.                         if(isset($this->hub_info['userlist'][$tmp]))
  182.                             unset($this->hub_info['userlist'][$tmp]);
  183.  
  184.                 }
  185.                 else if('To:' === $temp_cmd)       
  186.                 {
  187.                         if(!$this->control['connected']) break;
  188.  
  189.                         $msg_array = $this->get_private_message();
  190.                        
  191.                         if($msg_array !== false)
  192.                             $this->options['func_chat_private']($msg_array[0], $msg_array[1], $this);
  193.  
  194.                 }
  195.                 else if('UserCommand' === $temp_cmd)
  196.                 {
  197.                     break;
  198.                 }
  199.                 else if('Lock' === $temp_cmd)
  200.                 {
  201.                         if($this->control['connected']) break;
  202.                        
  203.                         preg_match("/Lock (.*) Pk/i", $this->curent_buffer, $lock);
  204.                        
  205.                         if($this->options['userlist'])
  206.                             $this->write_socket('$Supports NoHello');
  207.  
  208.                         $this->write_socket('$Key '.$this->lock2key($lock[1]));
  209.                         $this->write_socket('$ValidateNick '.$this->options['nickname']);
  210.                        
  211.                         if(!empty($this->options['password']))
  212.                             $this->write_socket('$MyPass '.$this->options['password']);
  213.  
  214.                 }
  215.                 else if('HubName' === $temp_cmd)
  216.                 {
  217.                         if($this->control['connected']) break;
  218.  
  219.                         $this->hub_info['hubname'] = substr($this->curent_buffer, 9);
  220.                    
  221.                 }
  222.                 else if('GetPass' === $temp_cmd)   
  223.                 {
  224.                         if($this->control['connected']) break;
  225.                        
  226.                         $this->options['func_event_handler']('GetPass', $this);
  227.                        
  228.                 }
  229.                 else if('ForceMove' === $temp_cmd)
  230.                 {
  231.  
  232.                     $this->options['func_event_handler']($this->curent_buffer, $this);
  233.                    
  234.                 }
  235.                 else if('HubIsFull' === $temp_cmd)
  236.                 {
  237.                    
  238.                     $this->disconnect();
  239.                     $this->options['func_event_handler']('$HubIsFull', $this);
  240.                    
  241.                 }
  242.  
  243.             }while(0);     
  244.            
  245.             // Free the memory
  246.             if($this->curent_buffer !== null)
  247.             {
  248.                 $this->curent_buffer = null;
  249.                 $temp_cmd = null;
  250.             }
  251.         }
  252.     }
  253.    
  254.     /**
  255.      * Function to send public messages. Can be used in Callback functions
  256.      *
  257.      * @access public
  258.      * @param string $msg
  259.      */
  260.     public function send_public_message($msg)
  261.     {
  262.         $this->write_socket('<'.$this->options['nickname'].'> '.$this->nmdcspecialchars($msg, true));
  263.     }
  264.    
  265.     /**
  266.      * Function to send private messages. Can be used in Callback functions
  267.      *
  268.      * @access public
  269.      * @param string $to
  270.      * @param string $msg
  271.      */
  272.     public function send_private_message($to, $msg)
  273.     {
  274.         $this->write_socket('$To: '.$to.' From: '. $this->options['nickname'].' $<'.$this->options['nickname'].'> '.$this->nmdcspecialchars($msg, true));
  275.     }
  276.    
  277.     /**
  278.      * Function of receiving commands, protocol NMDC
  279.      *
  280.      * @access private
  281.      */
  282.     private function get_cmd()
  283.     {
  284.         if($this->curent_buffer[0] === '<')
  285.             return '$CHAT';
  286.         elseif($this->curent_buffer[0] !== '$')
  287.             return false;
  288.    
  289.         return substr($this->curent_buffer, 1, strpos($this->curent_buffer, ' ')-1);
  290.     }
  291.    
  292.     /**
  293.      * Function for receiving public messages
  294.      *
  295.      * @access private
  296.      */
  297.     private function get_public_message()
  298.     {
  299.         $str_pos = strpos($this->curent_buffer, '>');
  300.         $msg_array[0] = substr($this->curent_buffer, 1, $str_pos-1);
  301.  
  302.         if($msg_array[0] === $this->options['nickname'])
  303.             return false;
  304.  
  305.         $msg_array[1] = $this->nmdcspecialchars(substr($this->curent_buffer, $str_pos+2), false);
  306.        
  307.         return $msg_array;
  308.     }
  309.    
  310.     /**
  311.      * Function for receiving private messages
  312.      *
  313.      * @access private
  314.      */
  315.     private function get_private_message()
  316.     {
  317.         $str_pos_first = strpos($this->curent_buffer, '<');
  318.         $str_pos_last = strpos($this->curent_buffer, '>', $str_pos_first);
  319.  
  320.         $msg_array[0] = substr($this->curent_buffer, $str_pos_first+1, $str_pos_last - $str_pos_first -1);
  321.  
  322.         if($msg_array[0] === $this->options['nickname'])
  323.             return false;
  324.  
  325.         $msg_array[1] = $this->nmdcspecialchars(substr($this->curent_buffer, $str_pos_last+2), false);
  326.        
  327.         return $msg_array;
  328.     }
  329.    
  330.     /**
  331.      * Function, character by character to read from socket
  332.      *
  333.      * @access private
  334.      */
  335.     private function read_socket()
  336.     {
  337.         while(1)
  338.         {
  339.             $return_data = socket_read($this->handle_connection, $this->socket_tcp_recvspace, PHP_BINARY_READ);
  340.            
  341.             if($return_data === false)
  342.             {
  343.                 return false;
  344.             }
  345.             else if($return_data === '')
  346.             {
  347.                 $this->reconnect();
  348.                 return true;
  349.             }
  350.            
  351.             $this->read_buffer .= $return_data;
  352.            
  353.             unset($return_data);
  354.  
  355.             $position = strrpos($this->read_buffer, '|');
  356.  
  357.             if($position === false)
  358.                 return false;
  359.            
  360.             $raw_data = explode('|', substr($this->read_buffer, 0, $position));
  361.            
  362.             foreach ($raw_data as $val)
  363.             {
  364.                 $this->read_buffer_array[] = $val;
  365.             }
  366.            
  367.             $raw_buffer = substr($this->read_buffer, $position+1);
  368.  
  369.             unset($position, $raw_data);
  370.            
  371.             if($raw_buffer === false)
  372.             {
  373.                 $this->read_buffer = null;
  374.                 return false;
  375.             }
  376.            
  377.             if(strlen($this->read_buffer) < $this->options['read_buffer_size'])
  378.             {
  379.                 $this->read_buffer = $raw_buffer;
  380.                 return false;
  381.             }
  382.  
  383.             $this->_debug('SYS(BUFFER OVERFLOW) - size: '.strlen($this->read_buffer).' max_size: '.$this->options['read_buffer_size']);
  384.             $this->options['func_event_handler']('sysbufoverflow', $this);
  385.             return false;
  386.         }
  387.     }
  388.    
  389.     /**
  390.      * Function write in socket
  391.      *
  392.      * @access private
  393.      */
  394.     private function write_socket($cmd)
  395.     {
  396.         $this->_debug("TX: $cmd");
  397.  
  398.         $cmd .='|';
  399.         $len = strlen($cmd);
  400.         $offset = 0;
  401.  
  402.         while ($offset < $len)
  403.         {
  404.             $sent = socket_write($this->handle_connection, substr($cmd, $offset), $len-$offset);
  405.             if($sent === false) {
  406.                 // Error occurred, break the while loop
  407.                 break;
  408.             }
  409.             $offset += $sent;
  410.            
  411.             if($offset < $len)
  412.                 $this->_debug('SOCKET_WRITE FRAG: len:'.$len.' writed: '.$offset);
  413.         }
  414.         if ($offset < $len)
  415.         {
  416.             $this->_debug('SOCKET_WRITE ERROR: '.socket_last_error());
  417.             return false;
  418.         }
  419.  
  420.         return true;
  421.     }
  422.    
  423.     /**
  424.      * Function for immediate reconnection
  425.      *
  426.      * @access private
  427.      */
  428.     public function reconnect()
  429.     {
  430.         if($this->control['connected'])
  431.         {
  432.             socket_close($this->handle_connection);
  433.         }
  434.        
  435.         $this->control['connected'] = false;
  436.         $this->hub_info['userlist'] = array();
  437.         $this->curent_buffer = null;
  438.         $this->read_buffer = null;
  439.         $this->read_buffer_array = array();
  440.                
  441.         $this->handle_connection = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  442.         socket_bind($this->handle_connection, $this->options['bind_ip']);
  443.        
  444.         $this->socket_tcp_recvspace = socket_get_option($this->handle_connection, SOL_SOCKET, SO_RCVBUF);
  445.        
  446.         socket_connect($this->handle_connection, $this->options['host'], $this->options['port']);
  447.         socket_set_nonblock($this->handle_connection);
  448.  
  449.         if($this->frequency != $this->options['frequency_low'])
  450.             $this->frequency = $this->options['frequency_low'];
  451.     }
  452.    
  453.     /**
  454.      * Function to disconnect
  455.      *
  456.      * @access public
  457.      */
  458.     public function disconnect()
  459.     {
  460.         $this->write_socket('$Quit');
  461.         $this->control['connected'] = false;
  462.         $this->hub_info['userlist'] = array();
  463.         socket_close($this->handle_connection);
  464.     }
  465.    
  466.     /**
  467.      * Function to send raw commands
  468.      *
  469.      * @access public
  470.      * @param string $command
  471.      */
  472.     public function send_raw_command($command)
  473.     {
  474.         $this->write_socket($command);
  475.     }
  476.    
  477.     /**
  478.      * Convert special characters in NMDC protocol
  479.      *
  480.      * @access private
  481.      * @param string $str
  482.      * @param bool $reverse
  483.      */
  484.     private function nmdcspecialchars($str, $reverse)
  485.     {
  486.         if($reverse)
  487.         {
  488.             $search = array('&#36;', '&#124;', '&amp;');
  489.             $replace = array('$', '|', '&');
  490.  
  491.             return str_replace($search, $replace, $str);
  492.         }
  493.         else
  494.         {
  495.             $search = array('&amp;', '&#36', '&#124;', '$', '|');
  496.             $replace = array('&amp;amp;', '&amp;#36', '&amp;#124;', '&#36;', '&#124;');
  497.            
  498.             return str_replace($search, $replace, $str);
  499.         }
  500.     }
  501.    
  502.     /**
  503.      * Function generation lock2key key to the protocol specification NMDC
  504.      *
  505.      * @access private
  506.      * @param string $_LOCK
  507.      */
  508.     private function lock2key($_LOCK)
  509.     {
  510.         $lockLength = strlen($_LOCK);
  511.         $LockToKey = '';
  512.  
  513.         for ($j = 0; $j < strlen($_LOCK); $j++)
  514.         {
  515.             if($j == 0) {
  516.                 $h = ord($_LOCK{0}) ^ ord( $_LOCK{ $lockLength - 1} ) ^ ord( $_LOCK{ $lockLength - 2} ) ^ 5;
  517.             }
  518.             else {
  519.                 $h = ord($_LOCK{$j}) ^ ord($_LOCK{$j-1});
  520.             }
  521.  
  522.             $h = $h % 256;
  523.  
  524.             $a = (($h<<4) & 240) | (($h>>4) & 15);
  525.  
  526.             if($a == '126' or $a == '124' or $a == '96' or $a == '36' or $a == '5' or $a == '0') {
  527.                 $LockToKey .= '/%DCN';
  528.  
  529.                   if ($a < 100) $LockToKey .= "0";
  530.                   if ($a < 10) $LockToKey .= "0";
  531.  
  532.                   $LockToKey .= $a.'%/';
  533.             }
  534.             else {
  535.                   $LockToKey .= chr($a);
  536.             }
  537.         }
  538.  
  539.         return $LockToKey;
  540.     }
  541.    
  542.     /**
  543.      * Function debugging, to monitor incoming and outgoing data
  544.      *
  545.      * @access private
  546.      * @param string $str
  547.      */
  548.     private function _debug($str)
  549.     {
  550.         if(!$this->options['debug'])
  551.             return;
  552.        
  553.         echo $str."\n\n";
  554.     }
  555.    
  556.     /**
  557.      * Function check error codes.
  558.      *
  559.      * @access private
  560.      */
  561.     private function sock_error_trigger()
  562.     {
  563.         $err_num = socket_last_error($this->handle_connection);
  564.  
  565.         if($err_num === 0) // *nix, Windows (In non-blocking mode when the connection is not established, but we're trying to read data from socket)
  566.             return false;
  567.         else if($err_num === 35) // *nix (tested on FreeBSD)
  568.             return false;
  569.         else if($err_num === 10035) // Windows (tested on Windows 7)
  570.             return false;
  571.         else
  572.             return true;
  573.     }
  574. }
  575.  
  576. ?>
Advertisement
Add Comment
Please, Sign In to add comment