Location: PHPKode > scripts > ABC Protocol > abc-protocol/ABCProtocol.php
<?php
    /* 
     * ABCProtocol
     * Version 1.0 BETA
     * Created by sk89q
     * http://www.therisenrealm.com
     * http://www.keiichianimeforever.com
     *
     * Copyright (c) 2005, sk89q
     * 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 sk89q nor the names of its 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, STRICT 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.
    */

    /**
     * ABCProtocol is an abstraction layer to ABC Web Interface Service (2.7 version)
     *
     * @package ABCProtocol
     * @author sk89q
     * @copyright Copyright (c) 2005, sk89q
     */
     
    /**
     * ABCProtocol is an abstraction layer to the ABC web interface service (2.7 version)
     *
     * @package ABCProtocol
     * @version 1.0 BETA
     * @author sk89q
     * @link http://pingpong-abc.sourceforge.net ABC [ Yet Another Bittorrent Client ] website
     * @link http://pingpong-abc.sourceforge.net/protocol_v3.txt protocol documentation
     * @copyright Copyright (c) 2005, sk89q
     */
    class ABCProtocol
    {
        /**
         * @var string hostname of computer hosting ABC
         */
        var $host               = 'localhost';
        /**
         * @var integer port of computer hosting ABC that ABC is running on
         */
        var $port               = 4000;
        /**
         * @var integer number of seconds to timeout connection
         */
        var $timeout            = 5;
        
        /**
         * @var string unique key set in ABC
         */
        var $unique_key         = '';
        
        /**
         * This property is set when an error occurs
         * @var integer error type (see constants)
         */
        var $last_error_type;
        /**
         * This property is set when an error occurs
         *
         * ERROR_PROTOCOL errors do not have an error number
         * @var integer error number 
         */
        var $last_error_no;
        /**
         * This property is set when an error occurs
         * @var string error string
         */
        var $last_error_str;
        /**
         * This property is set when a command is sent
         * @var string last command
         */
        var $last_command;
    
        /**
         * Constructor that defines constants and sets the default class properties
         *
         * @version 1.0
         * @param string $host hostname of target computer with ABC
         * @param integer $port port of target computer with ABC
         * @param string $unique_key unique_key set in ABC
         * @param integer $timeout connection timeout
         */
        function ABCProtocol( $host = 'localhost', $port = 4000, $unique_key = '', $timeout = 5 )
        {
            $this->host = $host;
            $this->port = $port;
            $this->unique_key = $unique_key;
            $this->timeout = $timeout;
        
            define( 'COL_FILENAME',             4 );
            define( 'COL_PROGRESS',             5 );
            define( 'COL_BT_STATUS',            6 );
            define( 'COL_PIORITY',              7 );
            define( 'COL_ETA',                  8 );
            define( 'COL_SIZE',                 9 );
            define( 'COL_DL_SPEED',             10 );
            define( 'COL_UL_SPEED',             11 );
            define( 'COL_UD_SIZE',              12 );
            define( 'COL_MESSAGE',              13 );
            define( 'COL_SEEDS',                14 );
            define( 'COL_PEERS',                15 );
            define( 'COL_COPIES',               16 );
            define( 'COL_PEER_AVG_PROGRESS',    17 );
            define( 'COL_DL_SIZE',              18 );
            define( 'COL_UL_SIZE',              19 );
            define( 'COL_TOTAL_SPEED',          20 );
            define( 'COL_TORRENT_NAME',         21 );
            define( 'COL_DESTINATION',          22 );
            define( 'COL_SEEDING_TIME',         23 );
            define( 'COL_CONNECTIONS',          24 );
            define( 'COL_SEEDING_OPTION',       25 );
            define( 'COL_INFO_HASH',            99 );
            
            define( 'ERROR_SOCKET',             100 );
            define( 'ERROR_PROTOCOL',           200 );
            
            define( 'ALL',                      100 );
            define( 'COMPLETED',                200 );
            define( 'RUNNING',                  300 );
        }
        
        /**
         * Sends a command to ABC
         *
         * If there is an error, the error properties of this class will be updated to reflect the error and 
         * FALSE will be returned.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->send_command( 'CLOSE|' );</code>
         * @version 1.0
         * @param string $query command line to send to ABC (unique key need not be prepended)
         * @return bool the success of the command; catches both connection errors and errors reported by ABC
         */
        function send_command( $query )
        {
            $this->last_command = $query;
            
            if( $fs = @fsockopen( $this->host, $this->port, $err_no, $err_str, $this->timeout ) )
            {
                fwrite( $fs, "ID|{$this->unique_key}\n$query" );
                
                while( !feof( $fs ) )
                {
                    $result .= fread( $fs, 1024 );
                }
                
                fclose( $fs );
                
                if( preg_match( "`^Feedback\nError=(.*)$`", $result, $err ) )
                {
                    $this->last_error_type = ERROR_PROTOCOL;
                    $this->last_error_no = -1;
                    $this->last_error_str = $err[1];
                    
                    return FALSE;
                }
                
                return $result;
            }
            else
            {
                $this->last_error_type = ERROR_SOCKET;
                $this->last_error_no = $err_no;
                $this->last_error_str = $err_str;
                
                return FALSE;
            }
        }
        
        /**
         * Closes ABC's web service
         *
         * Remember that once you close the web service, there isn't a protocol-based way to get it back up!<br /><br />
         * <b>Example Code</b>
         * <code>$abc->close();</code>
         * @version 1.0
         * @return bool the success of the command
         */
        function close()
        {
            $query = 'CLOSE|';
            
            if( !$result = $this->send_command( $query ) )
            {
                return FALSE;
            }
            
            return TRUE;
        }
        
        /**
         * Gets current version of ABC installed
         *
         * <b>Example Code</b>
         * <code>echo $abc->version();</code>
         * @version 1.0
         * @return mixed the version as a string or FALSE for error
         */
        function version()
        {
            $query = 'VERSION|';
            
            if( !$result = $this->send_command( $query ) )
            {
                return FALSE;
            }
            
            if( preg_match( "`^Version\n(.*)$`", $result, $ver ) )
            {
                return $ver[1];
            }
            
            return FALSE;
        }
        
        /**
         * Queries ABC for a list of torrents
         * 
         * Pass an array of fields. If no fields are passed, a default set of fields will be passed.<br /><br />
         * Note: Do not trust that the order of fields you send are received in the same order (especially if you send repeat fields)<br /><br />
         * <b>List of Fields (these are constants)</b>
         * <ul>
         * <li>COL_FILENAME</li>
         * <li>COL_PROGRESS</li>
         * <li>COL_BT_STATUS</li>
         * <li>COL_PIORITY</li>
         * <li>COL_ETA</li>
         * <li>COL_SIZE</li>
         * <li>COL_DL_SPEED</li>
         * <li>COL_UL_SPEED</li>
         * <li>COL_UD_SIZE</li>
         * <li>COL_MESSAGE</li>
         * <li>COL_SEEDS</li>
         * <li>COL_PEERS</li>
         * <li>COL_COPIES</li>
         * <li>COL_PEER_AVG_PROGRESS</li>
         * <li>COL_DL_SIZE</li>
         * <li>COL_UL_SIZE</li>
         * <li>COL_TOTAL_SPEED</li>
         * <li>COL_TORRENT_NAME</li>
         * <li>COL_DESTINATION</li>
         * <li>COL_SEEDING_TIME</li>
         * <li>COL_CONNECTIONS</li>
         * <li>COL_SEEDING_OPTION</li>
         * </ul>
         * COL_INFO_HASH will be a field gotten AUTOMATICALLY. Do <b>NOT</b> send this as a field! All your query results will have COL_INFO_HASH.<br /><br />
         * Your results will be an array with keys as the field and the values as the values<br /><br />
         * <b>Example Code</b>
         * <code>print_r( $abc->query( array( COL_FILENAME, COL_PROGRESS ) ) );
         *print_r( $abc->query() );</code>
         * <b>Example Results (outputted with print_r())</b>
         * <code>Array
         * (
         *     [0] => Array
         *         (
         *             [4] => [AonE]_Naruto_142_[A96A4B42].avi
         *             [5] => 100.0%
         *         )
         * )Array
         * (
         *     [0] => Array
         *         (
         *             [4] => [AonE]_Naruto_142_[A96A4B42].avi
         *             [5] => 100.0%
         *             [6] => stop
         *             [8] => 
         *             [10] => 
         *             [11] => 
         *             [12] => 49.7%
         *             [15] => 0 (388)
         *             [14] => 0 (531)
         *             [16] => 
         *             [18] => 174.29 MB
         *             [19] => 86.59 MB
         *             [17] => 
         *             [20] => 
         *             [99] => c6ef01d7f1fa5d458e31a37457fead490dfb7bf5
         *         )
         * )</code>
         * The key names appear as numbers but you can use $result[0][COL_TORRENT_NAME] or respectively.
         * @version 1.0
         * @param array $fields list of fields (the COL_ constants) to get for each torrent - do NOT use COL_INFO_HASH; if $fields is not defined, the default list of fields will be used
         * @return mixed list of current torrents or FALSE for error
         */
        function query( $fields = array() )
        {
            if( !is_array( $fields ) )
            {
                trigger_error( "Invalid argument 1 for " . __CLASS__ . "::" . __FUNCTION__ . "(); expected array", E_USER_ERROR );
            }
            
            if( count( $fields ) == 0 )
            {
                $fields = array(
                                COL_FILENAME,
                                COL_PROGRESS,
                                COL_BT_STATUS,
                                COL_ETA,
                                COL_DL_SPEED,
                                COL_UL_SPEED,
                                COL_UD_SIZE,
                                COL_PEERS,
                                COL_SEEDS,
                                COL_COPIES,
                                COL_DL_SIZE,
                                COL_UL_SIZE,
                                COL_PEER_AVG_PROGRESS,
                                COL_TOTAL_SPEED,
                                );
            }
        
            $query = 'QUERY|' . implode( ',', $fields );
            
            if( !$result = $this->send_command( $query ) )
            {
                return FALSE;
            }
            
            $data = array();
            
            $result = explode( "\n", $result );
            
            array_shift( $result );
            
            $fields[] = COL_INFO_HASH;
            
            foreach( $result as $line )
            {
                if( empty( $line ) )
                {
                    continue;
                }
                
                $line = explode( '|', $line );
                
                $data_line = array();
                
                for( $i = 0; $i < count( $line ); $i++ )
                {
                    $data_line[ $fields[ $i ] ] = $line[ $i ];
                }
                
                $data[] = $data_line;
            }
            
            return $data;
        }
        
        /**
         * Gets ABC parameter(s)
         * 
         * <b>Example Code</b>
         * <code>echo $abc->get_params( array( 'window_width', 'maxdownloadrate' ) );
         *echo $abc->get_params( 'window_width' );</code>
         * @version 1.0
         * @param mixed $params either an array of parameters to get or a string of a parameter to get
         * @return mixed either an array with param => value for multiple parameters or a value if only one parameter was requested
         */
        function get_params( $params )
        {
            if( !is_array( $params ) )
            {
                $params = array( $params );
                
                $not_array = TRUE;
            }
        
            $query = 'GETPARAM|' . implode( ',', $params );
            
            if( !$result = $this->send_command( $query ) )
            {
                return FALSE;
            }
            
            $result_array = array();
            
            if( !preg_match( "`^Feedback\n(.*)\n$`", $result, $res ) )
            {
                return FALSE;
            }
                
            $line = explode( '|', $res[1] );
            
            for( $i = 0; $i < count( $line ); $i++ )
            {
                if( !$params[ $i ] )
                {
                    continue;
                }
                
                $result_array[ $params[ $i ] ] = $line[ $i ];
            }
            
            if( $not_array )
            {
                return $result_array[ $params[0] ];
            }
            else
            {
                return $result_array;
            }
        }
        
        /**
         * Set ABC parameters
         *
         * Will return FALSE if one command does not go through.<br /><br />
         * Note: For each parameter, a new command will be sent. When all the parameters were sent at once, the error <i>Command should end with |</i> kept appearing and a solution could not be found.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->set_params( array( 'window_width' => 500 ) );</code>
         * @version 1.0
         * @param mixed $params either an array of parameters to set or a string of a parameter to set
         * @return bool the success of the command
         */
        function set_params( $params )
        {
            if( !is_array( $params ) )
            {
                trigger_error( "Invalid argument 1 for " . __CLASS__ . "::" . __FUNCTION__ . "(); expected array", E_USER_ERROR );
            }
            
            $params_set_string = array();
            foreach( $params as $conf => $val )
            {
                $params_set_string[] = "$conf=$val";
            }
            
            // Using one command kept giving a "Command should end with |" ????
            foreach( $params_set_string as $param )
            {
                $query = 'SETPARAM|' . $param;
                
                if( !$result = $this->send_command( $query ) )
                {
                    return FALSE;
                }
            }
            
            return TRUE;
        }
        
        /**
         * Gets language string from ABC
         *
         * If you request an inexistant language string from ABC, ABC will popup a message box on the server for the first time that will state that an outdated language file is being used.<br /><br />
         * <b>Example Code</b>
         * <code>print_r( $abc->get_lang_strings( array( 
         *      'superseederrornotcompleted', 
         *      'superwarningmsg_line2',
         *      ) ) );
         *print_r( $abc->get_lang_strings( 'superseederrornotcompleted' ) );</code>
         * @version 1.0
         * @param mixed $names either an array of language strings to get or a string of a language string to get
         * @return mixed either an array with string => value for multiple language strings or a value if only one language string was requested
         */
        function get_lang_strings( $names )
        {
            if( !is_array( $names ) )
            {
                $names = array( $names );
                
                $not_array = TRUE;
            }
            
            $result_array = array();
            
            foreach( $names as $name )
            {
                $query = 'GETSTRING|' . $name;
                
                if( !$result = $this->send_command( $query ) )
                {
                    continue;
                }
                
                if( !preg_match( "`^String\n(.*)$`", $result, $res ) )
                {
                    continue;
                }
                
                $result_array[ $name ] = $res[1];
            }
            
            if( $not_array )
            {
                return $result_array[ $names[0] ];
            }
            else
            {
                return $result_array;
            }
        }
        
        /**
         * Internal processor for torrent changes such as STOP, PAUSE, etc.
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion regardless of status)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: COMPLETED and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->change_torrent_status( 'DELETE', array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->change_torrent_status( 'DELETE', 'abcdef01234569abcdef01234569abc1' );
         *$abc->change_torrent_status( 'PAUSE', ALL );
         *$abc->change_torrent_status( 'DELETE', COMPLETED );</code>
         * @version 1.0
         * @access private
         * @param string $command command to tell ABC (such as STOP, PAUSE, etc.)
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function change_torrent_status( $command, $torrents )
        {
            if( $torrents == ALL )
            {
                $torrents = 'ALL';
            }
            
            $mask = $torrents;
            
            if( $mask == COMPLETED || $mask == RUNNING )
            {
                $torrents = array();
                
                if( $query = $this->query( array( COL_PROGRESS ) ) )
                {
                    foreach( $query as $torrent )
                    {
                        if( $mask == COMPLETED && trim( $torrent[ COL_PROGRESS ] ) == '100.0%' )
                        {
                            $torrents[] = $torrent[ COL_INFO_HASH ];
                        }
                        elseif( $mask == RUNNING && trim( $torrent[ COL_PROGRESS ] ) != '100.0%' )
                        {
                            $torrents[] = $torrent[ COL_INFO_HASH ];
                        }
                    }
                }
                else
                {                    
                    return FALSE;
                }
            }
            
            if( empty( $torrents ) || count( $torrents ) == 0 )
            {
                return TRUE;
            }
            
            if( !is_array( $torrents ) )
            {
                $torrents = array( $torrents );
            }
            
            $query = $command . '|' . implode( ',', $torrents );
            
            if( !$result = $this->send_command( $query ) )
            {
                return FALSE;
            }
            
            return TRUE;
        }
        
        /**
         * Pauses torrent(s)
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion regardless of status)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: COMPLETED and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->pause_torrents( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->pause_torrents( 'abcdef01234569abcdef01234569abc1' );
         *$abc->pause_torrents( ALL );
         *$abc->pause_torrents( COMPLETED );</code>
         * @version 1.0
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function pause_torrents( $torrents )
        {
            return $this->change_torrent_status( 'PAUSE', $torrents );
        }
        
        /**
         * Unpauses torrent(s)
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion regardless of status)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: COMPLETED and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->unpause_torrents( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->unpause_torrents( 'abcdef01234569abcdef01234569abc1' );
         *$abc->unpause_torrents( ALL );
         *$abc->unpause_torrents( COMPLETED );</code>
         * @version 1.0
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function unpause_torrents( $torrents )
        {
            return $this->change_torrent_status( 'UNPAUSE', $torrents );
        }
        
        /**
         * Resumes torrent(s)
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion regardless of status)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: COMPLETED and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->resume_torrents( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->resume_torrents( 'abcdef01234569abcdef01234569abc1' );
         *$abc->resume_torrents( ALL );
         *$abc->resume_torrents( COMPLETED );</code>
         * @version 1.0
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function resume_torrents( $torrents )
        {
            return $this->change_torrent_status( 'RESUME', $torrents );
        }
        
        /**
         * Stops torrent(s)
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion regardless of status)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: COMPLETED and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->stop_torrents( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->stop_torrents( 'abcdef01234569abcdef01234569abc1' );
         *$abc->stop_torrents( ALL );
         *$abc->stop_torrents( COMPLETED );</code>
         * @version 1.0
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function stop_torrents( $torrents )
        {
            return $this->change_torrent_status( 'STOP', $torrents );
        }
        
        /**
         * Queues torrent(s)
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion regardless of status)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: COMPLETED and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->queue_torrents( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->queue_torrents( 'abcdef01234569abcdef01234569abc1' );
         *$abc->queue_torrents( ALL );
         *$abc->queue_torrents( COMPLETED );</code>
         * @version 1.0
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function queue_torrents( $torrents )
        {
            return $this->change_torrent_status( 'QUEUE', $torrents );
        }
        
        /**
         * Deletes torrent(s)
         *
         * Instead of passing an array of torrent hashes, you may also send the following constants:
         * <ul>
         * <li>ALL</li>
         * <li>COMPLETED <i>(all tasks with 100% completion)</i></li>
         * <li>RUNNING <i>(all tasks without 100% completion regardless of status)</i></li>
         * </ul>
         * Note: ALL and RUNNING are not native features of the protocol so this function automatically
         * sends a query for a list of torrents and then processes that list of torrents.<br /><br />
         * <b>Example Code</b>
         * <code>$abc->delete_torrents( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );
         *$abc->delete_torrents( 'abcdef01234569abcdef01234569abc1' );
         *$abc->delete_torrents( ALL );
         *$abc->delete_torrents( COMPLETED );</code>
         * @version 1.0
         * @param mixed $torrents array of torrent info hashes, constant ALL, constant COMPLETED, constant RUNNING, or one info hash as string
         * @return bool the success of the command
         */
        function delete_torrents( $torrents )
        {
            if( $torrents == COMPLETED )
            {
                $torrents = 'COMPLETED';
            }
            
            $mask = $torrents;
            
            if( $mask == ALL || $mask == RUNNING )
            {
                $torrents = array();
                
                if( $query = $this->query( array( COL_PROGRESS ) ) )
                {
                    foreach( $query as $torrent )
                    {
                        if( $mask == ALL )
                        {
                            $torrents[] = $torrent[ COL_INFO_HASH ];
                        }
                        elseif( $mask == RUNNING && trim( $torrent[ COL_PROGRESS ] ) != '100.0%' )
                        {
                            $torrents[] = $torrent[ COL_INFO_HASH ];
                        }
                    }
                }
                else
                {                    
                    return FALSE;
                }
            }
            
            if( empty( $torrents ) || count( $torrents ) == 0 )
            {
                return TRUE;
            }
            
            if( !is_array( $torrents ) )
            {
                $torrents = array( $torrents );
            }
            
            $query = 'DELETE|' . implode( ',', $torrents );
            
            if( !$result = $this->send_command( $query ) )
            {
                return FALSE;
            }
            
            return TRUE;
        }
        
        /**
         * Adds a single torrent
         *
         * Supports setting a save location ONLY IF set parameters and get parameters are enabled in ABC for the web service (disabled by default).<br /><br />
         * <b>Example Code</b>
         * <code>$abc->add_torrent( 'http://file1.torrent' );
         *$abc->add_torrent( 'http://file1.torrent', 'C:\\Downloads\\' );</code>
         * @version 1.0
         * @param string $torrent the URL to the torrent file
         * @param string $location the save location
         * @return bool the success of the command
         */
        function add_torrent( $torrent, $location = '' )
        {
            return $this->add_torrents_list( array( array( $torrent, $location ) ) );
        }
        
        /**
         * Adds a list of torrents
         *
         * <b>List of Torrent URLs</b>
         * <code>$abc->add_torrents_list( array( 'http://file1.torrent', 'http://file2.torrent' ) );</code>
         * <b>List of Torrent URLs with Save Location</b>
         * <code>$abc->add_torrents_list( array( 
         *      array( 'http://file1.torrent', '/path/to/save/1' ), 
         *      array( 'http://file2.torrent', '/path/to/save/2' ) ),
         *      );</code>
         * Supports setting a save location ONLY IF set parameters and get parameters are enabled in ABC for the web service (disabled by default)
         * @version 1.0
         * @param array $torrents pass an array such as array( 'http://file1.torrent', 'http://file2.torrent' ) OR for URLs with save locations, use array( array( 'http://file1.torrent', '/path/to/save/1' ), array( 'http://file2.torrent', '/path/to/save/2' ) )
         * @return bool the success of the command
         */
        function add_torrents_list( $torrents )
        {
            if( !is_array( $torrents ) )
            {
                $torrents = array( $torrents );
            }
            
            foreach( $torrents as $torrent )
            {
                $old_params = array();
                
                if( is_array( $torrent ) )
                {
                    if( !empty( $torrent[1] ) )
                    {
                        if( count( $old_params ) == 0 )
                        {
                            if( !$old_params = $this->get_params( array(
                                'setdefaultfolder',
                                'defaultfolder',
                                ) ) )
                            {
                                return FALSE;
                            }
                        }
                        
                        if( !$this->set_params( array(
                            'defaultfolder' => $torrent[1],
                            'setdefaultfolder' => '1',
                            ) ) )
                        {
                            return FALSE;
                        }
                    }
                    
                    $torrent = $torrent[0];
                }
                
                $query = 'ADD|' . $torrent;
                
                if( !$result = $this->send_command( $query ) )
                {
                    return FALSE;
                }
            }
            
            if( count( $old_params ) != 0 )
            {
                $this->set_params( array(
                    'setdefaultfolder' => $old_params['setdefaultfolder'],
                    'defaultfolder' => $old_params['defaultfolder'],
                    ) );
            }
            
            return TRUE;
        }
        
        /**
         * Sets priorities of torrents
         *
         * <b>Example Code</b>
         * <code>$abc->set_torrent_priorities( array( 
         *      'abcdef01234569abcdef01234569abc1' => 4, 
         *      'abcdef01234569abcdef01234569abc2' => 2,
         *      ) );</code>
         * Piorities range from 0 to 4; use info hashes to identify torrents<br /><br />
         * Note: For each parameter, a new command will be sent. When all the parameters were sent at once, the error <i>Command should end with |</i> kept appearing and a solution could not be found.
         * @version 1.0
         * @param array $torrents pass an array such as array( 'abcdef01234569abcdef01234569abc1' => 4,'abcdef01234569abcdef01234569abc2' => 2 ); piorities range from 0 to 4
         * @return bool the success of the command
         */
        function set_torrent_priorities( $torrents )
        {
            if( !is_array( $torrents ) )
            {
                trigger_error( "Invalid argument 1 for " . __CLASS__ . "::" . __FUNCTION__ . "(); expected array", E_USER_ERROR );
            }
            
            $torrents_set_string = array();
            foreach( $torrents as $hash => $piority )
            {                
                if( !in_array( $piority, array( 0, 1, 2, 3, 4 ) ) )
                {
                    trigger_error( "Piority not whole number >= 0 and <= 4 for $hash", E_USER_WARNING );
                }
                else
                {
                    $torrents_set_string[] = "$hash,$piority";
                }
            }
            
            if( count( $torrents_set_string ) == 0 )
            {
                return TRUE;
            }
            
            // Using one command kept giving a "Command should end with |" ????
            foreach( $torrents_set_string as $torrent )
            {
                $query = 'PRIORITY|' . $torrent;
                
                if( !$result = $this->send_command( $query ) )
                {
                    return FALSE;
                }
            }
            
            return TRUE;
        }
    }
?>
Return current item: ABC Protocol