Location: PHPKode > projects > Nzbirc > nzbirc-1.4/modules/nzb.php
<?php

/**************************************************
 * NZBirc v1
 * Copyright (c) 2006 Harry Bragg
 * tiberious.org
 * Module: nzb
 **************************************************
 *
 * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 * 
 */

class Net_SmartIRC_module_nzb extends Net_SmartIRC_module_base
{

	// default module variable
	var $name = 'nzb';
	var $version = 'v0.7';
	var $description = 'interfaces with v3.newzbin.com';
	
	/**
	 * Newzbin Module - Please note the commands are regex's www.regular-expressions.info for a very good reference.
	 *
	 * STARTCONFIG
	 * @var array publicCommand  - Lists the commands that trigger this module, and return publicly
	 * @var array privateCommand - Lists the commands that trigger this module privatly (notice you)
	 * @var bool nbLogin         - Login to newzbin.com or not
	 * @var array login
	 * @var     string username  - Newzbin.com username
	 * @var     string password  - Newzbin.com password
	 * @var array download
	 * @var     bool useHella    - use HellaNZB to download nzb files (less error checking, req: hellanzb)
	 * @var     string nzbPath   - path to store all the nzb files
	 * @var     bool nickPreface - Add a (nickname) at the beginning of each nzb file for ident later
	 * @var     int history      - Number of days to keep a history of nzb's that have been downloded
	 * @var 	bool hideDnzbWait- Hide the Waiting for nzb's/5 minute message
	 * @var string language      - if you only want results from a particular language, specify it here
	 * @var int searchResults    - How many results you want to return from a search result (default: 4)
	 * @var int maxPages         - How many pages to search for in deep mode, num results = n*100, so 5 = 500 results (default: 5)
	 * @var int reportCache      - The number of days to keep reports info before re-requesting their information
	 * @var double cacheChange   - Probability of using the cache instead of re-querying (between 0 and 1, 0.9 = 90%)	 
	 * ENDCONFIG
	 */
	var $_config = array(
		'publicCommand' => array( '^nzb', '^!nzb' ),
		'privateCommand' => array( '^@nzb' ),
		'nbLogin' => false,
		'login' => array(
			'username' => 'username',
			'password' => 'password' ),
		'download' => array(
			'useHella' => false,
			'nzbPath' => '/path/to/nzb/',
			'nickPreface' => true,
			'history' => 14,
			'hideDnzbWait' => true ),
		'language' => '',
		'searchResults' => 4,
		'maxPages' => 5,
		'reportCache' => 1.1,
		'cacheChance' => 0.95
	);
	
	/**
	 * newzbin.com definition listing
	 */
	var $_def = array(
		'url' => array(
			'search' => 'http://www.newzbin.com/search/query/?fpn=p&q=%s&category=-1&searchaction=Go&feed=rss&u_post_results_amt=100&page=%d',
			'urlsearch' => 'http://www.newzbin.com/search/query/?fpn=p&q=%s&q_url=%s&category=-1&searchaction=Go&feed=rss&u_post_results_amt=100&page=%d',								
			'report' => 'http://www.newzbin.com/browse/post/%d/',
			'login' => 'http://www.newzbin.com/account/login/',
			'download' => 'http://v3.newzbin.com/api/dnzb/'
		),
		'regex' => array(
			'search' => array(
				/**
				 * 1 => title
				 * 2 => id
				 * 3 => url
				 * 4 => category
				 * 5 => reportTime
				 */
				'result' => '/<item>\s+<title>(.+)<\/title>\s+<guid isPermaLink="true">http:\/\/.+\.newzbin\.com\/browse\/post\/(\d+)\/<\/guid>\s+<link>http:\/\/.+\.newzbin\.com\/browse\/post\/\d+\/<\/link>\s+<comments>http:\/\/.+\.newzbin\.com\/browse\/post\/\d+\/#CommentsPH<\/comments>\s+<description>\s+More Info: (.+)\s+Group: .+\s+Cat: (.+), SubCat:.+\s+<\/description>\s+<pubDate>(.+)<\/pubDate>\s+<\/item>/i',
				'specific' => '/.*%s.*/i',
				'urlmatch' => '/<item>\s+<title>(.+)<\/title>\s+<guid isPermaLink="true">http:\/\/.+\.newzbin\.com\/browse\/post\/(\d+)\/<\/guid>\s+<link>http:\/\/.+\.newzbin\.com\/browse\/post\/\d+\/<\/link>\s+<comments>http:\/\/.+\.newzbin\.com\/browse\/post\/\d+\/#CommentsPH<\/comments>\s+<description>\s+More Info: (%s)\s+Group: .+\s+Cat: (.+), SubCat:.+\s+<\/description>\s+<pubDate>(.+)<\/pubDate>\s+<\/item>/i',
				'queryExpansion' => '/^(.*?)\{([^\}]+)\}(.*)$/i',
				'numberSearch' => '/(?:(\d+)-(\d+)|([^-,]+))/',
				'flags' => '/(.+)\sf(?:lags?)?:([a-z0-9,.\s\&\(\)\~\|\-\+\/]+)/i',
				'tvrage' => 'http:\/\/www\.tvrage\.com\/%s\/episodes\/%s.*?'
				),
			'report' => array(
				'title' => array(
					'regex' => '/<title id="title">Newzbin - Report \d+: (.+)<\/title>/i',
					'vals' => array( 1 => 'title' ) ),
/*				'size' => array(
					'regex' => '/<span class="fileSize">([0-9,.]+)MB<\/span> total\s+<br \/>\s+Decoded:/i',
					'vals' => array( 1 => 'report:size' ) ),
				'filename' => array(
					'regex' => array(
						'/<\/span>\s+.+&quot;(.+)&quot;.+\s+<\/td>\s+<\/tr>\s+<tr>\s+<td class="center">/i',
						'/<\/span>\s+.+\-\s(.+)(?!\-)\s+<\/td>\s+<\/tr>\s+<tr>\s+<td class="center">/i' ),
					'vals' => array( 1 => 'filename' ) ),
				'url' => array(
					'regex' => '/<img alt="URL" src="\/m\/i\/i\/url.png" \/>&nbsp;(.+)<\/a>/i',
					'vals' => array( 1 => 'url' ) ),
				'files' => array(
					'regex' => '/<th>Size:<\/th>\s+<td>\s+(\d+) files,\s+(\d+) data,\s+(\d+) recovery/',
					'vals' => array( 1 => 'files', 2 => 'dataFiles', 3 => 'recoveryFiles' ) ),
				'status' => array(
					'regex' => '/<th>Status:<\/th>\s+<td>\s+<span title="[^"]+">(.+)<\/span>\s+<\/td>/i',
					'vals' => array( 1 => 'status' ) ),
				'progress' => array(
					'regex' => '/<th>Progress:<\/th>\s+<td>\s+<img title="[^"]+" alt="([^"]+)"/i',
					'vals' => array( 1 => 'progress' ) ),
				'nfo' => array(
					'regex' => '/<img alt="NFO" src="\/m\/i\/i\/nfo.png" \/>&nbsp;(.+)<\/a>/i',
					'vals' => array( 1 => 'nfo' ) ),
				'reported' => array(
					'regex' => '/<th>Reported:<\/th>\s+<td>\s+(.+)\s+\(<span class="/i',
					'vals' => array( 1 => 'reported' ) ),
				'post' => array(
					'regex' => '/<\/span>\s+(.+)\s+<\/td>\s+<\/tr>\s+<tr>\s+<td class="center">/i',
					'vals' => array( 1 => 'post' ) ), */
			),
			'reportInfo' => array(
				'rawAttributes' => '/<th>Attributes:<\/th>\s+<td>(?s:(.+?))<\/td>\s+<\/tr>/i',
				'attribute' => '/\s*([a-z\s]+):\s+(?s:([a-z\s,]+))\s*<br \/>/i',
				'value' => '/\s*([a-z\s]+),?/i',
				'specificFilename' => '/<\/span>\s+.*%s.*\s+<\/td>\s+<\/tr>\s+<tr>\s+<td class="center">/i',
				'isReport' => '/<li class="error"><span>Error:<\/span> That Report does not exist!<\/li>/i'
			),
			'add' => array(
				'next' => '/^next$/i',
				'force' => '/^force$/i',
				'split' => '/(\+|\!|\^|\-)(\d{7,9})/i',
				'url' => '/(http:\/\/)?[a-z0-9_\-.\/]+\/([a-z0-9_\-.\/]+)/i' ),
			'loggedIn' => array(
				'/<div class="user">\s+<strong>Guest<\/strong>/i',
				'!/<report:attribute/i' ),
			'download' => array(
				'DNZBwait' => '/Try Later, wait (\d+) seconds for counter to reset/i' )
		),
		'date' => array(
			'history' => array(
				'time' => 'h:ia'
			)
		),
		'flagtype' => array(
			's' => 'Source',
			'vf' => 'Video Fmt',
			'vg' => 'Video Genre',
			'af' => 'Audio Fmt',
			'ag' => 'Audio Genre',
			'r' => 'Region',
			'st' => 'Subtitles',
			'l' => 'Language',
			'm' => 'Media',
			'a' => 'Anime',
			'mi' => 'Music Info',
			'gg' => 'Game Genre',
			'c' => 'Console Platform',
			'cp' => 'Console Platform',
			'p' => 'Platform',
			'b' => 'Book Type',
			'bg' => 'Book Genre'
		),
		'searchAttributeIgnore' => array(
			'Video Genre',
			'Audio Genre'
		),
		'replace' => array(
			'fileToTitle' => array(
				'from' => array( '_' ),
				'to' => array( ' ' )
			),
			'titleToFile' => array(
				'from' => array(' ', '..', '.', '?', ':', '#', '<', '>', '/', '\\', '|', '*', '\'', '"', '&amp;' ),
				'to' => array( '_' )
			)
		)
	);
	
	/**
	 * Template system
	 */	 
	var $_template = array(
		'search' => '({nzbid}) {category}: __{progress}__{title} | {attributes} [{reported}, {size}] {file}',
		'attributes' => '{type}:{format}',
		'report' => array(
			'({nzbid}) {category}: __{progress}__{title} [{size}, reported: {reported}] link: {link}',
			'Attributes: [{attributes}] | url: {url}{logBridge}' ),
		'logBridge' => '{log}',
		'log' => '[**{date}**: {action}]',
		'addSucc' => 'Queued: [{addQueued}]',
		'addQueued' => '{id}:{title}{flagMatchBridge}',
		'flagMatchBridge' => '',
		'flagMatch' => ' (**{flag}**)',
		'addError' => 'Error: [{addQueued}]',
		'history' => '[**{date}**] {nzbHistory}',
		'nzbHistory' => '({time}) {id}: {title}',
		'error' => '**Error:** {errormsg}',
		'commandList' => 'List of commands available for NZB | type {trigger} help command, for more information on each command',
		'help' => '{command} - {description}',
		'helpList' => array(
			'Commands available for NZB: {helpCommands}',
			'Type: {trigger} {subTrigger} command, for more information on each command'
			)
		);
	
	var $_help = array(
		'help' => array(
			'command' => '{trigger} help [command]',
			'description' => 'Display the available commands, if a __command__ is specified, then extra information is provided',
			'longDescription' => 'Display the available commands, if a __command__ is specified, then extra information is provided'
			),
		'commands' => array(
			'command' => '{trigger} commands',
			'description' => 'List the available commands with their descriptions',
			'longDescription' => 'List the available commands with their descriptions'
			),
		'forceadd' => 'add',
		'nextadd' => 'add',
		'enqueue' => 'add',
		'forceenqueue' => 'add',
		'nextenqueue' => 'add',
		'add' => array(
			'command' => '{trigger} [force/next]add query [f:flags]',
			'description' => 'Download nzb files based on the __query__, which can be one or more NZBid\'s, or a search query',
			'longDescription' => array(
				'Download nzb files based on the __query__, which can be a NZBid, or a search query',
				'The search query can include **variables**, for example: {{01,02,09-20}}, will add 01, 02, 09, 10, ... 20',
				'This also works with words {{cat,mouse,dog}} will add cat, mouse and dog seperatly. Multiple **variables** can be defined in a single query',
				'Flags, define the quality of files to be downloaded, more information can be found with {trigger} help search',
				'REQ: HellaNZB, If force or next are placed before the add part, the nzb\'s downloaded will be placed in the approprate places in the queue',
				'Alternative command: + (see {trigger} help +)'
				)
			),
		'!' => '+',
		'^' => '+',
		'-' => '+',
		'+' => array(
			'command' => '{trigger} +/!/^/-nzbid [+/!/^/-nzbid2 [...]]',
			'description' => 'the same as {trigger} add/del, but it will only accept nzbID\'s from newzbin.com, **+** adds, **!** adds and forces, **^** adds and places next in the queue, **-** deletes, (**!**,**^** and **-** depends on HellaNZB)',
			'longDescription' => array(
				'the same as {trigger} add/del, but it will only accept nzbID\'s from newzbin.com',
				'**+** adds, **!** adds and then forces the nzb, **^** adds and places next it in the queue, **-** deletes from the queue'
				)
			),
		'search' => array(
			'command' => '{trigger} search query [f:flags]',
			'description' => 'Searches newzbin based on the query, if __flags__ are specified, the results are based on their flags',
			'longDescription' => array(
				'Searches newzbin based on the query, if __flags__ are specified, the results are based on their flags',
				'The current flags are all attributes that exist on newzbin.com',
				'Multiple flags: placing a , in between flags indicates a different set of flags to search for',
				'Order: The order of the flags, specifies their priority, placing them earlier makes them more important, ie: 720p,xvid means 720p is more important',
				'Logic: Simple logic can be used to combine flags, ie: 720p&x264 will only match both 720p and x264',
				'see http://www.tiberious.org/wiki/index.php/Nzbirc/v1/flags for more information'
				)
			),
		'report' => 'info',
		'post' => 'info',
		'info' => array(
			'command' => '{trigger} info/report/post nzbid [nzbid2 [nzbid3 ...]]',
			'description' => 'Obtain information about a newzbin report, from its ID',
			'longDescription' => 'Obtain information about a newzbin report, from its ID'
			),
		'history' => array(
			'command' => '{trigger} history date/duration',
			'description' => 'Return the nzb\'s downloaded on the specified __date__, or __duration__',
			'longDescription' => array(
				'Return the nzb\'s downloaded on the specified __date__, or __duration__',
				'__date__ can be in almost any date format: today, next wednesday, 10/11/06, 15th Jan 06, etc',
				'__duration__ is in the format: Xw Yd',
				'date periods can be specified using **-** or **to**, these will list items between 2 absolute dates/durations, i.e.: {trigger} history -4d to yesterday',
				'the joining word **for** can also be used for relative periods, i.e.: {trigger} history 15 dec 06 for 3d',
				'see http://www.tiberious.org/wiki/index.php/Nzbirc/v1/times for more information'
				)
			)
		);

	/**
	 * Store temporary errors
	 */
	var $_error;
	
	/**
	 * XML Unserialiser
	 * 
	 * @var XML_Unserialzer $_fromXML
	 */
	var $_fromXML;
	
	function _registerCommands()
	{
	 	global $irc;
	 	
		$this->_setHandler( '^search', $this, 'doSearch' );
		
		$this->_setHandler( '^(info|report|post)', $this, 'doInfo' );
		
		$this->_setHandler( '^(add|enqueue)', $this, 'add' );
		$this->_setHandler( '/\+(\d{7,9})/i', $this, 'addSplit' );
		if ( $irc->isLoadedModule( 'hella' ) )
		{
			$this->_setHandler( '^(force|next)(add|enqueue)', $this, 'add' );
			$this->_setHandler( '/(\^|\!|\-)(\d{7,9})/i', $this, 'addSplit' );
		}
		
		$this->_setHandler( '^history', $this, 'history' );

		//help
		$this->_setHandler( '^help', $this, 'botHelp' );
		$this->_setHandler( '^commands', $this, 'botCommands' );
		
		$irc->_modules['store']->addVariable( '_nzbCache' );
		$irc->_modules['store']->addVariable( '_nzbCookie' );
		$irc->_modules['store']->addVariable( '_nzbHistory' );
		$irc->_modules['store']->addVariable( '_nzbWait' );
		$irc->_modules['store']->addVariable( '_nzbQueued' );
		$irc->_modules['store']->addVariable( '_nzbQError' );
		
		// store this incase the program shuts down mid dnzb queue parse
		$irc->_modules['store']->addVariable( '_nzbDnzbQueue' );
		
		$irc->_nzbTimerID = $irc->registerTimeHandler( 5000, $this, 'checknzb' );
		
		$options = array(
			XML_UNSERIALIZER_OPTION_RETURN_RESULT    => true,
			XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => true,
			XML_UNSERIALIZER_OPTION_FORCE_ENUM       => array(
				'item',
				'report:attribute'
			),
			XML_UNSERIALIZER_OPTION_ENCODING_SOURCE  => $irc->config->encoding
		);
		
		$this->_fromXML = &new XML_Unserializer( $options );
		
		if ( count( $irc->_nzbDnzbQueue ) > 0 )
		{
			$this->flushDNZB( $irc );	
		}
	}
	
	function _customClose()
	{
		global $irc;
		
		$irc->unregisterTimeid( $irc->_nzbTimerID );
	}
	
	/*****************************************************
	 * Bot functions
	 *****************************************************/	
	
	function doSearch( &$irc, &$data, $notice )
	{
		// check to see if flags are specified
		if ( preg_match( $this->_def['regex']['search']['flags'], $data->subMessage, $match ) )
		{
			$flags = explode(',', $match[2]);
			$query = $match[1];
		}
		else 
		{
			$query = $data->subMessage;
			$flags = array();
		}
		
		$results = $this->search( $query, $this->_config['searchResults'], $flags );
		
		if ( count( $results ) == 0 )
		{
			$irc->_modules['func']->reply( $irc, $data, 'No results found for: '.$data->subMessage, $notice );
		}
		
		foreach( $results as $res )
		{
			// check res for result
			if ( isset( $res['report:id'] ) )
			{			
				// filter result into string and output
				$vars = array(
					'nzbid' => $res['report:id'],
					'category' => $res['report:category'],
					'reported' => trim( $irc->_modules['func']->snicedate( $res['report:reported'] ) ),
					'title' => $res['report:title'] );

				$vars['progress'] = ( $res['report:progress']['value'] != 1 )? $res['report:progress']['_content'].', ':'';
				
				$vars['size'] = $irc->_modules['func']->humanSize( $res['report:size']['_content']);
				$vars['file'] = 'file: '.$res['report:nfo']['report:filename'];
				
				if ( is_array( $res['report:attributes']['sorted'] ) )
				{
					foreach( $res['report:attributes']['sorted'] as $key => $arr )
					{
						if ( !in_array( $key, $this->_def['searchAttributeIgnore'] ) )
						{
							$tmp = array(
								'type' => $key,
								'format' => $arr
							);
							$vars['attributes'][] = $tmp;
						}
					}
				}
				
				$this->parseTemplate( $msg, 'search', $vars );
			}
			
			unset( $out, $vars );
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}
	
	function doInfo( &$irc, &$data, $notice )
	{	
	 	$subMex = explode( ' ', $data->subMessage );
	 	$irc->_modules['store']->manualUpdate( '_nzbHistory' );
	 	
	 	foreach( $subMex as $nzbID )
		{
			if ( is_numeric( $nzbID ) )
			{
				if ( ( $res = $this->getReport( $nzbID ) ) !== false )
				{
					// check res for result
					if ( isset( $res['report:id'] ) )
					{			
						// filter result into string and output
						$vars = array(
							'nzbid' => $res['report:id'],
							'category' => $res['report:category'],
							'reported' => trim( $irc->_modules['func']->snicedate( $res['report:reported'] ) ),
							'title' => $res['report:title'] );
		
						$vars['progress'] = ( $res['report:progress']['value'] != 1 )? $res['report:progress']['_content'].', ':'';
						
						$vars['size'] = $irc->_modules['func']->humanSize( $res['report:size']['_content']);
						$vars['file'] = 'file: '.$res['report:nfo']['report:filename'];
						
						$vars['link'] = $res['report:link'];
						$vars['url'] = $res['report:moreinfo'];
						
						if ( is_array( $res['report:attributes']['sorted'] ) )
						{
							foreach( $res['report:attributes']['sorted'] as $key => $arr )
							{
								if ( !in_array( $key, $this->_def['searchAttributeIgnore'] ) )
								{
									$tmp = array(
										'type' => $key,
										'format' => $arr
									);
									$vars['attributes'][] = $tmp;
								}
							}
						}
						
						if ( isset( $irc->_nzbHistory[$res['report:id']] ) )
						{
							$vars['logBridge'] = ' | History: {log}';
							
							foreach( $irc->_nzbHistory[$res['report:id']]['log'] as $lEntry )
							{
								$vars['log'][] = array(
									'date' => $irc->_modules['func']->snicedate( $lEntry['time'] ),
									'action' => $lEntry['action'] );
							}
						}
						
						$this->parseTemplate( $msg, 'report', $vars );
					}
				}
				else
				{
					$irc->_modules['func']->reply( $irc, $data, 'Report: '.$nzbID.' does not exist', $notice );
				}
			}
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}
	
	function add( &$irc, &$data, $notice )
	{
	 	$data->notice = $notice;
	 	$hellaMod = false;
		if ( count( $data->trig ) > 2 )
		{
			// hella moving stuffs
			if ( preg_match( $this->_def['regex']['add']['next'], $data->trig[1] ) )
			{
				$hellaMod = 'next';				
			}
			else if ( preg_match( $this->_def['regex']['add']['force'], $data->trig[1] ) )
			{
				$hellaMod = 'force';
			}
		}
		
		$data->hellaMod = $hellaMod;
		
		$subMessageex = explode( ' ', $data->subMessage );
		
		if ( ( !is_numeric( $subMessageex[0] ) ) || ( strlen($subMessageex[0]) < 5 ) )
		{
			// check to see if flags are specified
			if ( preg_match( $this->_def['regex']['search']['flags'], $data->subMessage, $match ) )
			{
				$flags = explode(',', $match[2]);
				$query = $match[1];
			} 
			else 
			{
				$query = $data->subMessage;
				$flags = array();
			}
				
			// check if it is a url
			if ( preg_match( $this->_def['regex']['add']['url'], $data->subMessage ) )
			{
				$results[] = array(
					'id' => '117114108'.rand(10000,99999),
					'url' => $data->subMessage
					);
			}
			else
			{		
				$results = $this->search( $query, 1, $flags );
				
				if ( count( $results ) == 0 )
				{
					$irc->_modules['func']->reply( $irc, $data, 'No results found for: '.$data->subMessage, $notice );
				}
			}
			
		}
		else
		{
			foreach( $subMessageex as $id )
			{
				$results[] = array( 'id' => $id );
			}
		}	
	
		if ( ( $irc->config->useWorker == true ) &&
		     ( $irc->isWorker == false ) )
		{
			$irc->_modules['store']->manualUpdate( '_nzbWait' );
			foreach( $results as $res )
			{				
				if ( isset( $res['id'] ) )
				{
					$irc->_nzbWait[$res['id']] = array(
						'id' => $res['id'],
						'data' => $irc->_modules['func']->getTData( $data ) 
					);
				}
				else if ( isset( $res['report:id'] ) )
				{
					$irc->_nzbWait[$res['report:id']] = array(
						'id' => $res['report:id'],
						'data' => $irc->_modules['func']->getTData( $data ) 
					);
				}
			}
			$irc->_modules['store']->manualUpdate( '_nzbWait', true );
			return;
		}
		
		foreach( $results as $res )
		{
			if ( substr( $res['id'], 0, 9 ) == '117114108' )
			{
				if ( ( $title = $this->_addUrl( $res['id'], $res['url'] ) ) !== false )
				{
			 	 	$succ[] = array(
					  'id' => $res['id'],
					  'title' => $title );
			 	}
			 	else
			 	{
					$errors[] = array(
					  'id' => $res['id'],
					  'title' => $this->_error );
				}
			}
		 	else if ( isset( $res['id'] ) )
		 	{
			 	if ( ( $title = $this->_addID( $res['id'], $data, $hellaMod ) ) !== false )
			 	{
			 		$val = array(
						'id' => $res['id'],
						'title' => $title);
			 		
			 		if ( isset( $irc->_nzbCache[$res['id']] ) )
			 		{
			 			if ( isset( $irc->_nzbCache[$res['id']]['flagMatch'] ) )
			 			{
			 				$val['flagMatchBridge'] = '{flagMatch}';
							$val['flagMatch'][]['flag'] = $irc->_nzbCache[$res['id']]['flagMatch'];
			 			}
			 		}
			 		 	 				 		
			 	 	$succ[] = $val;
			 	}
			 	else
			 	{
			 	 	if ( !preg_match( $this->_def['regex']['download']['Dnzbwait'], $this->_error ) )
			 	 	{
						$errors[] = array(
						  'id' => $res['id'],
						  'title' => $this->_error );					
					}
					else
					{
						$wait[] = $res['id'];
					}
				}
			}
		}
		
		$vars['seperator'] = ', ';
		if ( is_array( $succ ) )
		{
			$vars['addQueued'] = $succ;
			$this->parseTemplate( $msg, 'addSucc', $vars );
		}
		if ( ( isset( $wait ) ) && ( !$this->_config['download']['hideDnzbWait'] ) )
		{
			$errors[] = array(
				'id' => implode( ',', $wait ),
				'title' => 'Waiting for Newzbin\'s 5nzbs/minute limit to timeout' );
		} 
		if ( is_array( $errors ) )
		{
			$vars['addQueued'] = $errors;
			$this->parseTemplate( $msg, 'addError', $vars );
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}
	
	function addSplit( &$irc, &$data, $notice )
	{
	 	$data->notice = $notice;
		if ( preg_match_all( $this->_def['regex']['add']['split'], $data->strippedMessage, $ids ) > 0 )
		{
			$irc->_modules['store']->manualUpdate( '_nzbWait' );
		 	for( $i = 0; $i < count( $ids[0] ); $i++ )
		 	{
				// delete
				if ( $ids[1][$i] == '-' )
				{
					if ( $irc->isLoadedModule( 'hella' ) )
					{
						if ( $irc->_modules['hella']->del( $tmp, $ids[2][$i] ) )
						{
							$succ[] = array(
								'id' => $ids[2][$i],
								'title' => $tmp[0] );
						}
						else
						{
							$errors[] = array(
								'id' => $ids[2][$i],
								'title' => $tmp[0] );
						}
					}
				}
				else
				{
					$hellaMod = ( $ids[1][$i] == '!' )? 'force':
								( ( $ids[1][$i] == '^' )? 'next':false );
								
					$data->hellaMod = $hellaMod;
					
					if ( ( $irc->config->useWorker == true ) &&
						 ( $irc->isWorker == false ) )
					{
						$irc->_nzbWait[$ids[2][$i]] = array(
							'id' => $ids[2][$i],
							'data' => $data );
					}
					else
					{
						if ( ( $title = $this->_addID( $ids[2][$i], $data, $hellaMod ) ) !== false )
						{
							$succ[] = array(
							  'id' => $ids[2][$i],
							  'title' => $title );
						}
						else
						{
							if ( !preg_match( $this->_def['regex']['download']['DnzbWait'], $this->_error ) )
							{
								$errors[] = array(
								  'id' => $ids[2][$i],
								  'title' => $this->_error );					
							}
							else
							{
								$wait[] = $ids[2][$i];
							}
						}
					}
				}
			}
		}

		if ( ( $irc->config->useWorker == true ) &&
			 ( $irc->isWorker == false ) )
		{
			$irc->_modules['store']->manualUpdate( '_nzbWait', true );
		}

		$vars['seperator'] = ', ';
		if ( is_array( $succ ) )
		{
			$vars['addQueued'] = $succ;
			$this->parseTemplate( $msg, 'addSucc', $vars );
		}
		if ( ( isset( $wait ) ) && ( !$this->_config['download']['hideDnzbWait'] ) )
		{
			$errors[] = array(
				'id' => implode( ',', $wait ),
				'title' => 'Waiting for Newzbin\'s 5nzbs/minute limit to timeout' );
		} 
		if ( is_array( $errors ) )
		{
			$vars['addQueued'] = $errors;
			$this->parseTemplate( $msg, 'addError', $vars );
		}

		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
	}
	
	function history( &$irc, &$data, $notice )
	{ 
		list( $date, $date2 ) = $irc->_modules['func']->dateDurationParse( $data->subMessage );
			
		$date = $irc->_modules['func']->dateToDay( $date );
		if ( $date2 >= 0 )
			$date2 = $irc->_modules['func']->dateToDay( $date2 );
		
		$nzbs = $this->_getHistory( $date, $date2 );
		
		if ( count( $nzbs ) > 0 ) 
		{
			foreach( $nzbs as $id => $item )
			{
			 	$vars = array(
					'date' => $irc->_modules['func']->snicedate( $id )
				);
			 	
				foreach( $item as $nzb )
				{
				 	$tmp = array(
				 		'time' => date( $this->_def['date']['history']['time'], $nzb['queued'] ),
				 		'id' => $nzb['id'],
				 		'title' => $nzb['title']
				 	);
					$vars['nzbHistory'][] = $tmp;
				}
				
				$this->parseTemplate( $msg, 'history', $vars );
				
			}
		}
		else
		{
			$msg[] = 'No results found for the times specified';
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
		}
		
	}

	function botHelp( &$irc, &$data, $notice )
	{
		if ( strlen( $data->subMessage ) > 0 )
		{
			if ( isset( $this->_help[$data->subMessage] ) )
			{
				$this->parseHelp( $msg, $data->subMessage, array( 'trigger' => $data->trigger ) );
			}
			else
			{
				//$this->parseTemplate( $msg, 'error', array( 'errormsg' => sprintf( 'Unknown command: %s', $data->subMessage ) ) );
			}
		}
		else
		{
			foreach ( $this->_help as $id => $helpItem )
			{
				$vars['helpCommands'][] = $id;
			}
			$vars['trigger'] = $data->trigger;
			$vars['subTrigger'] = $data->trig[0];
			$this->parseTemplate( $msg, 'helpList', $vars );
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, true );
		}
		
	}
	
	function botCommands( &$irc, &$data, $notice )
	{
		$vars['trigger'] = $data->trigger;
		
		$this->parseTemplate( $msg, 'commandList', $vars );
		
		foreach( $this->_help as $id => $helpItem )
		{
			if ( is_array( $helpItem ) )
			{
				$helpItem['trigger'] = $data->trigger;
				$this->parseTemplate( $msg, 'help', $helpItem );			
			}
		}
		
		if ( isset( $msg ) )
		{
			$irc->_modules['func']->reply( $irc, $data, $msg, true );
		}
	}	
	
	/*****************************************************
	 * Main functions
	 *****************************************************/	

	/**
	 * Add a newzbinID, with a specified modifier
	 *
	 * @param int $id          - Newzbin.com ID
	 * @param string $nick     - Nickname of the person who added the nzb
	 * @param string $modifier - modifiy the item in the queue afterwards (Default: false)
	 * @return bool/string     - string containing nzb report title, or false if failed
	 * @access private
	 */
	function _addID( $id, &$data, $modifier = false )
	{
	 	global $irc;
	 	
	 	$irc->modDebug( 'nzb', 'adding nzbID: '. $id .' to download queue', __FILE__, __LINE__, SMARTIRC_DEBUG_MODULES );
	 	
		// check to see if report exists
		if ( ( $rep = $this->getReport( $id ) ) !== false )
		{
		 	if ( ( $this->_config['download']['useHella'] ) && ( $irc->isLoadedModule( 'hella' ) ) )
		 	{
				// do hellahella stuff here
				if ( $irc->_modules['hella']->_send( 'enqueuenewzbin', array( $id ) ) !== false )
				{
					
					$irc->_modules['store']->manualUpdate( '_nzbHistory' );
					// add the item to history
					if ( isset( $irc->_nzbHistory[$id] ) )
					{
						$irc->_nzbHistory[$id]['log'][] = array(
							'time' => time(),
							'action' => 'queued' );
						
						$irc->_nzbHistory[$id]['data'] = $irc->_modules['func']->getTData( $data );
						$irc->_nzbHistory[$id]['queued'] = time();
						
						$irc->_modules['store']->manualUpdate( '_nzbHistory', true );	
					}
					else
					{
	 				 	$irc->_modules['store']->setVariable( '_nzbHistory', 
	 				 		array(
						  		'id' => $id,
								'queued' => time(),
								'data' => $irc->_modules['func']->getTData( $data ),
								'title' => $rep['report:title'],
	 				 			'log' => array(
	 				 				array( 'time' => time(), 'action' => 'queued' ) ) 
	 				 			),
	 				 		$id );
					}

					if ( ( $modifier ) || ( $data->hellaMod ) )
					{
						if ( $data->hellaMod )
							$modifier = $data->hellaMod;
						
						$ta = array( 'last' => -2, 'next' => -1, 'force' => 0 );
						if ( isset( $ta[$modifier] ) )
						{
							$irc->_modules['hella']->moveItem( $id, $ta[$modifier], $irc->_modules['func']->getTData( $data ) );
						}
					}
					
					// remove any old episodes in the history
					$this->_checkHistory();
 				 	
 					return $rep['report:title'];
				}
				else
				{
					$this->_error = $irc->_modules['hella']->_error;
					return false;
				}			
			}
			else
			{
 				$filetitle = trim( str_replace( array( ' ','..','.','?',':','#','<','>','/','\\','|','*','\'','"','&' ), '_', html_entity_decode( $rep['report:title'] ) ), '_' );
 				
 				$filename = $this->_config['download']['nzbPath'] . sprintf( 'msgid_%d_%s%s.nzb', $id, (( $this->_config['download']['nickPreface'] )? '('.$data->nick.')_':'' ), $filetitle );
 				
 				if ( ( $err = $this->_downloadDNZB( $id, $filename, $data ) ) === true )
 				{
 					$irc->_modules['store']->manualUpdate( '_nzbHistory' );
					// add the item to history
					if ( isset( $irc->_nzbHistory[$id] ) )
					{
						$irc->_nzbHistory[$id]['log'][] = array(
							'time' => time(),
							'action' => 'queued' );
						$irc->_nzbHistory[$id]['data'] = $irc->_modules['func']->getTData( $data );
						$irc->_nzbHistory[$id]['queued'] = time();
						
						$irc->_modules['store']->manualUpdate( '_nzbHistory', true );	
					}
					else
					{
						$irc->_modules['store']->setVariable( '_nzbHistory', 
							array(
						  		'id' => $id,
								'queued' => time(),
								'data' => $irc->_modules['func']->getTData( $data ),
								'title' => $rep['report:title'],
								'log' => array( array( 'time' => time(), 'action' => 'queued') ) ),
							$id );
					}
					
					if ( ( ( $modifier ) || 
					       ( $data->hellaMod ) ) && 
					     ( $irc->isLoadedModule( 'hella' ) ) )
					{
						if ( $data->hellaMod )
							$modifier = $data->hellaMod;
						
						$ta = array( 'last' => -2, 'next' => -1, 'force' => 0 );
						if ( isset( $ta[$modifier] ) )
						{
							$irc->_modules['hella']->moveItem( $id, $ta[$modifier], $irc->_modules['func']->getTData( $data ) );
						}
					}
											
					// remove any old episodes in the history
					$this->_checkHistory();
 				 	
 					return $rep['report:title'];
 				}
 				else
 				{
 				 	$this->_error = $err;
 					return false;
				}
			}
		}
		else
		{
			$this->_error = 'Report ID: '. $id .', does not exist';
			return false;
		}		
	}

	function _addUrl( $id, $url, $modifer = false )
	{
		global $irc;
		
		if ( preg_match( $this->_def['regex']['add']['url'], $url, $match ) )
		{
			$file = $match[1];
	
			if ( ( $err = $this->_downloadURL( $url, $file ) ) === true )
			{
				$rep['title'] = trim( str_replace( $this->_def['replace']['fileToTitle']['from'], $this->_def['replace']['fileToTile']['to'], $file ) );
				
				$irc->_modules['store']->addVariable( '_nzbHistory', 
					array(
						'id' => $id,
						'url' => $url,
						'queued' => time(),
						'data' => $irc->_modules['func']->getTData( $data ),
						'title' => $rep['title'] ),
					$id
				);					
				
				if ( ( $modifier ) && ( $irc->isLoadedModule( 'hella' ) ) )
				{
					if ( isset( $ta[$modifier] ) )
					{
						$ta = array( 'last' => -2, 'next' => -1, 'force' => 0 );					 
						$irc->_modules['hella']->moveItem( $id, $ta[$modifier], $irc->_modules['func']->getTData( $data ) );
					}
				}
										
				// remove any old episodes in the history
				$this->_checkHistory();
				
				return $rep['title'];
			}
			else
			{
				$this->_error = $err;
				return false;
			}
		}
	}
	

	/*****************************************************
	 * History
	 *
	 * The history is only stored for 2 weeks 
	 * (or the number of days you speicified in the config)
	 *****************************************************/

	/**
	 * Get the history from a day, or region of days
	 *
	 * @var int $date	- First date
	 * @var int $date2  - Second date | Default: false
	 * @return array    - The reports downloaded during the periods
	 * @access private
	 */
	function _getHistory( $date, $date2 = false )
	{
	 	global $irc;
	 
	 	if ( ( !$date2 ) || ( $date2 < 0 ) )
	 	{
	 	 	// date2 = 1 day after date
			$date2 = $date + 3600 * 24;
		}
		else
		{
			// make date2 + 1 day
			$date2 = $date2 + (3600 * 24) - 1;
		}
		
		if ( is_array( $irc->_nzbHistory ) )
		{
			foreach( $irc->_nzbHistory as $id => $item )
			{
				if ( ( $item['queued'] >= $date ) &&
				     ( $item['queued'] <= $date2 ) )
				{
					$out[$id] = $item;
					$downloaded[$id] = $item['queued'];
				}
			}
			
			if ( count( $out ) > 0 )
			{
				// all nicely ordered
				array_multisort( $downloaded, SORT_ASC, $out );
				
				foreach( $out as $item )
				{
					$ret[$irc->_modules['func']->dateToDay( $item['queued'] )][] = $item;
				}
			}
		}
		
		return $ret;
	}

	/**
	 * Check the nzb history, for old reports
	 *
	 * @return void
	 */
	function _checkHistory()
	{
	 	global $irc;
	 
        foreach( $irc->_nzbHistory as $id => $history )
        {
			if ( $history['queued'] < ( time() - ( $this->_config['download']['history'] * 3600 * 24 ) ) )
			{
				$irc->_modules['store']->unsetVariable( '_nzbHistory', $id );
			}
		}
	}
	

	/*****************************************************
	 * Search
	 *****************************************************/
	 
	/**
	 * Search for some nzb posts
	 *
	 * @param string $query - Query to search for
	 * @param int $results  - Number of results to return, 0 = all
	 * @param array $flags  = List of flags to conform to, default: empty, i.e. first result
	 * @returns array       - All the results in an array
	 * @access public
	 */
	function search( $query, $results, $flags = array() )
	{	
		global $irc;
	
		$res = array();
	
		// check to see if the query contains a variable
		if ( preg_match( $this->_def['regex']['search']['queryExpansion'], $query, $varMatch ) )
		{
			// see if there is a second variable in the query
			if ( preg_match( $this->_def['regex']['search']['queryExpansion'], $varMatch[3] ) )
			{			
				// get all the numbers in the first variable
				$nums = $this->_getSearchNumbers( $varMatch[2] );
				
				foreach( $nums as $num ) 
				{				
					$tmp = $this->search( sprintf( '%s%s%s', $varMatch[1], $num, $varMatch[3] ), 1, $flags );
					$irc->_modules['func']->array_append( $res, $tmp );
				}
				
				return $res;
				
			}
			else
			{ // have to do this, otherwise there would be too many searches on newzbin.com
				$query = $varMatch[1].' '.$varMatch[3];
				
				$matches = $this->_searchQuery( $query );
								
				// search through the variable
				$nums = $this->_getSearchNumbers( $varMatch[2] );
				
				foreach( $nums as $num ) 
				{					
					$regex = sprintf( $this->_def['regex']['search']['specific'], str_replace( array( ' ', '"' ), array( '.*', '' ), sprintf( '%s%s%s', $varMatch[1], $num, $varMatch[3] ) ) );
					
					$specificMatch = $this->_matchFilter( $matches, $regex );
										
					$tmp = $this->_flagFilter( $specificMatch, 1, $flags );
					if ( is_array( $tmp ) ) {
						$res[] = $tmp[0];
					}
				}
				
				if ( count( $res ) > 0 )
				{
					$irc->_modules['store']->manualUpdate( '_nzbCache' );
					foreach( $res as $r )
					{
						$irc->_nzbCache[$r['report:id']] = $r;
					}
					$irc->_modules['store']->manualUpdate( '_nzbCache', true );
				}
				
				return $res;
				
			}
		}
		
		$deep = ( count( $flags ) > 0)? true:false;
		$matches = $this->_searchQuery( $query, 1, false, $deep );
			
		$res = $this->_flagFilter( $matches, $results, $flags );
		
		if ( count( $res ) > 0 )
		{
			$irc->_modules['store']->manualUpdate( '_nzbCache' );
			foreach( $res as $r )
			{
				$irc->_nzbCache[$r['report:id']] = $r;
			}
			$irc->_modules['store']->manualUpdate( '_nzbCache', true );
		}

		return $res;
	}
	
	/**
	 * Filter a set of matches by a regex
	 *
	 * @param array $matches - Matches produced by searchQuery
	 * @param string $regex - Regular Expression to match against the title
	 * @return array - matches that fit the filter
	 * @access private
	 */
	function _matchFilter( $matches, $regex )
	{
		$ret = array();
		foreach( $matches as $m )
		{
			if ( preg_match( $regex, $m['report:title'] ) )
			{
				$ret[] = $m;
			}
		}
		
		return $ret;
	}
	
	/**
	 * Perform the actual search procedure
	 *
	 * @param string $query - query to send to newzbin
	 * @param integer $pageNum - Which page to return
	 * @param mixed $link - urlencoded url to search for (default: false)
	 * @param boolean $deep - should we do a deep search (get 500 results, instead of 100)
	 * @return array - All the results in _splitXml format
	 * @access private
	 */
	function _searchQuery( $query, $pageNum = 1, $link = false, $deep = true )
	{
		global $irc;
		
		if ( $link !== false )
		{
			$url = sprintf( $this->_def['url']['searchurl'], urlencode( $query ), $link, $pageNum );
		}
		else
		{
			$url = sprintf( $this->_def['url']['search'], urlencode( $query ), $pageNum );
		}
		
		ini_set( 'memory_limit', ($irc->config->memoryAllocation * 4).'M' );
		
		// do the search
		$page = $this->_getUrl( $url );
		
		// parse the xml
		$xmlData = $this->_fromXML->unserialize( $page );	
		unset( $page );		
		if ( PEAR::isError( $xmlData ) )
		{
			$irc->modDebug( 'nzb', 'XML Unserialization failed: '.$xmlData->getMessage(), __FILE__, __LINE__, SMARTIRC_DEBUG_MODULES );
			return array();
		}
				
		// do something with the xml here :]
		$matches = $this->_splitXml( $xmlData );
		unset( $xmlData );
		
		ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
		
		$irc->modDebug( 'nzb', sprintf( 'Query: %s, Page: %d, Results: %d', $query, $pageNum, count( $matches ) ), __FILE__, __LINE__ );
		
		if ( ( count( $matches ) == 100 ) && ( $deep ) )
		{
			// maximum number of pages to fetch (n = 5, n*100 = 500 results)
			if ( $pageNum < $this->_config['maxPages'] )
			{
				// get some more results and append
				$irc->_modules['func']->array_append( $matches, $this->_searchQuery( $query, ($pageNum + 1), $link ) );
			}
		}
		
		return $matches;
	}
	
	/**
	 * Search for some nzb posts
	 *
	 * @param string $query  - newzbin.com search query
	 * @param string $showID - TVrage show ID
	 * @param string $epID   - TVrage episode ID
	 * @param int $results   - Number of results to return, 0 = all
	 * @param array $flags   - List of flags to conform to, default: empty, i.e. first result
	 * @returns array        - All the results in an array
	 * @access public
	 */	
	function idSearch( $query, $showID, $epID, $results, $flags = array() )
	{	
		global $irc;
	
		$res = array();
		
		$deep = ( count( $flags ) > 0)? true:false;
		$matches = $this->_searchQuery( $query, 1, urlencode( sprintf( $this->_def['regex']['search']['tvrage'], $showID, $epID ) ), $deep );

		$res = $this->_flagFilter( $matches, $results, $flags );

		if ( count( $res ) > 0 )
		{
			$irc->_modules['store']->manualUpdate( '_nzbCache' );
			foreach( $res as $r )
			{
				$irc->_nzbCache[$r['report:id']] = $r;
			}
			$irc->_modules['store']->manualUpdate( '_nzbCache', true );
		}
		
		return $res;
	}
	
	/**
	 * Split up the report xml data
	 *
	 * @param array $xmlData
	 * @return array - Neatly formatted results
	 */
	function _splitXml( $xmlData )
	{	
		$ret = array();
		
		if ( is_array( $xmlData['channel']['item'] ) )
		{
			foreach( $xmlData['channel']['item'] as $item )
			{		
				$narr = array(
					'report:title' => $item['title'],
					'report:link' => $item['link'] );
				
				foreach( $item as $key => $val )
				{
					if ( substr( $key, 0, 6 ) == 'report' )
					{
						$narr[$key] = $val;
					}
				}
				
				$ret[] = $narr;
			}
		}
		
		return $ret;
	}
	
	/**
	 * Filter result by flags
	 *
	 * @param array $results - Search results
	 * @param int $numRes    - Number of results to return
	 * @param array $flags   - Flags
	 * @param bool $sort 	 - Sort the list based on flags
	 * @return array		 - Only the relevant results are kept
	 * @access private
	 */
	function _flagFilter( $results, $numRes, $flags, $sort = true )
	{
		global $irc;
		
		$res = array();
		$score = array();
		$age = array();
			
		foreach( $results as $nres )
		{
		    /**
			 * 1 => title
			 * 2 => id
			 * 3 => url
			 * 4 => category
			 * 5 => reported
			 */

			preg_match( '/^(\w+), (\d+) (\w+) (\d+) (\d+):(\d+):(\d+)/i', $nres['report:postdate'], $tMatch );
			$time = strtotime( sprintf( '%d %s %d %d:%d:%d', $tMatch[2], $tMatch[3], $tMatch[4], $tMatch[5], $tMatch[6], $tMatch[7] ) );
			
			$nres['report:reported'] = $time;

			// filter attributes
			$nres['report:attributes']['sorted'] = $this->_arrangeAttributes( $nres['report:attributes']['report:attribute'] );
			
			$nres['searched'] = time();
			
			// check if the post is complete
			if ( $nres['report:progress']['value'] == 1)
			{
				// check language
				if ( ( empty( $this->_config['language'] ) ) ||
				     ( empty( $nres['report:attributes']['sorted']['Language'] ) ) ||
					 ( in_array( $this->_config['language'], $nres['report:attributes']['sorted']['Language'] ) ) )
				{
					// do we need to match flags
					if ( count( $flags ) > 0 )
					{									
						$ts = $this->_scoreFlags( $flags, $nres['report:attributes'] );
						
						if ( $ts > 0 ) {
							$nres['score'] = $ts;
							$nres['flagMatch'] = $flags[count($flags) - $ts];
							$res[] = $nres;
						}
					} 
					else 
					{
						if ( $r < $numRes )
						{
							$nres['score'] = 0;
							$res[] = $nres;
						}
					}
				}
			}
		}
			
		if ( ( $sort ) && count( $res > 0 ) )
		{
		 	foreach( $res as $key => $row )
		 	{
				$score[$key] = $row['score'];
				$age[$key] = $row['report:reported'];
			}
		 
			array_multisort( $score, SORT_DESC, $age, SORT_DESC, $res );

			$res = array_slice( $res, 0, $numRes );
		}
		
		return $res;
	}
	
	/**
	 * Produce a score based on a set of flags and attributes
	 *
	 * @param array $flags - List of flags to test 
	 * @param array $attribs - Attributes to test against 'report:attributes'
	 * @return float - Score of the result (higher the better)
	 * @access private
	 */
	function _scoreFlags( $flags, $attribs )
	{
		global $irc;
		
		for( $i=0; $i < count($flags); $i++)
		{
			if ( $this->_checkFlags( $flags[$i], $attribs ) )
			{
				return count($flags) - $i;
			}
			
			// special case
			if ( in_array( $flags[$i], array( 'any', 'normal' ) ) )
			{
				return count($flags) - $i;
			}
		}
		
		return 0;
	}
	
	/**
	 * Split up the flags
	 *
	 * @param string $flags - String representation of flags logic
	 * @param array $attribs - List of attributes to test against
	 * @return boolean - result of the logic
	 * @access private
	 * @example 's~dvd&(vf~x264|vf~xvid)' = true/false 
	 */
	function _checkFlags( $flags, $attribs )
	{
		// if no logic characters are left, perform a simple flag check
		if ( !preg_match( '/[\+&\|\(\)]/i', $flags ))
		{
			return $this->_checkFlag( $flags, $attribs );
		}
		
		// loop through character at a time, checking syntax
		for ( $i=0; $i < strlen( $flags ); $i++ )
		{		
			switch( $flags[$i] )
			{
				case '&':
				case '+':
					{
						if ($i == 0)
							return $this->_checkFlags(substr($flags, 1), $attribs);
						else
							return ( $this->_checkFlags( substr( $flags, 0, $i ), $attribs ) && 
							         $this->_checkFlags( substr( $flags, $i + 1 ), $attribs ) );
					}
				case '|':
					{
						if ($i == 0)
							return $this->_checkFlags( substr( $flags, 1 ), $attribs );
						else
							return ( $this->_checkFlags( substr( $flags, 0, $i ), $attribs ) ||
									 $this->_checkFlags( substr( $flags, $i + 1 ), $attribs ) );
						break;	
					}
				case '(':
					{
						if ( $i != 0 )
						{
							global $irc;

							$irc->modDebug( 'nzb', 'Flag Logic failed, ( in the wrong place: '.$flags, __FILE__, __LINE__ );
							
							return false;
						}
						
						$rpos = strrpos( $flags, ')' );
						if ( $rpos === false)
						{
							global $irc;

							$irc->modDebug( 'nzb', 'Flag Logic failed, need closing parenthesis: '.$flags, __FILE__, __LINE__ );
							
							return false;
						}
						
						if ($rpos == strlen( $flags ) - 1)
						{
							return $this->_checkFlags( substr( $flags, 1, -1 ), $attribs );
						}
						else
						{
							$i = $rpos;
						}
						
						break;
					}
			}
		}
	}
	
	/**
	 * Check an individual flag
	 *
	 * @param string $flag - A single flag (xvid, s~dvd)
	 * @param array $attribs - List of attributes
	 * @return boolean - is the flag in the attributes
	 */
	function _checkFlag( $flag, $attribs )
	{		
		// does the flag have an attribute type
		if ( strstr( $flag, '~' ) )
		{
			$type = substr( $flag, 0, strpos( $flag, '~' ) );
			$mflag = substr( $flag, strpos( $flag, '~' ) + 1);
						
			$ltype = $this->_def['flagtype'][$type];
			
			if ( isset( $attribs['sorted'][$ltype] ) )
			{			
				foreach( $attribs['sorted'][$ltype] as $attr )
				{
					if (strtolower( $attr ) == strtolower($mflag))
						return true;
				}
			}
			return false;
		}
		else
		{
			foreach( $attribs['report:attribute'] as $attr )
			{
				if (strtolower($attr['_content']) == strtolower($flag))
				{
					return true;
				}
			}
			return false;
		}
	}
	
	/**
	 * Arrange the attributes from rss format to array format
	 *
	 * @param array $attribs - Attributes to arrange 
	 * @return array - Array with the attributes displayed correctly
	 * @access private
	 */
	function _arrangeAttributes( $attribs )
	{
		$res = array();
		
		if ( is_array( $attribs ) )
		{
			foreach( $attribs as $attr )
			{
				$res[$attr['type']][] = $attr['_content'];				
			}
		}
		
		return $res;
	}
	
	/**
	 * Gets the numbers inside a {01-05,06} variale
	 *
	 * @param string $variable - List of numbers
	 * @returns array 		   - Of all the numbers
	 * @access private
	 */
	function _getSearchNumbers( $variable ) {
		
		$res = array();
		
		if ( preg_match_all( $this->_def['regex']['search']['numberSearch'], $variable, $matches ) )
		{
			for( $i = 0; $i < count( $matches[0] ); $i++ ) 
			{
				if ( !empty( $matches[3][$i] ) ) {
					$res[] = $matches[3][$i];
				}
				else 
				{
					$len = strlen( $matches[1][$i] );
					for ( $j = $matches[1][$i]; $j <= $matches[2][$i]; $j++ ) {
						$res[] = sprintf( '%0'.$len.'d', $j);
					}
				}
			}
		}
		
		return $res;
		
	}

	/*****************************************************
	 * Report
	 *****************************************************/
	
	/**
	 * Get details of a newzbin.com report
	 *
	 * @param int $id - Report ID
	 * @return array  - Information related to the report
	 * @access public
	 */
	function getReport( $id ) {
		
		global $irc;
		
		$res = array(
			'nzbid' => $id
			);
		
		$irc->_modules['store']->manualUpdate('_nzbCache');
			
		// check cache
		if ( isset( $irc->_nzbCache[$id] ) ) {
		 	// found cache
			if ( ( $irc->_nzbCache[$id]['searched'] > time() - ( $this->_config['reportCache'] * 3600 * 24 ) ) &&
				 ( mt_rand(1, 100) <= (100 * $this->_config['cacheChance']) ) )
			{
				$irc->modDebug( 'nzb', 'report ID: '.$id.', using cache', __FILE__, __LINE__ );
				return $irc->_nzbCache[$id];
			}
		}
		
		$url = sprintf( $this->_def['url']['report'], $id );
		$page = $this->_getUrl( $url );
		
		//$res['page'] = $page;
		
		// check if it is a report
		if ( preg_match( $this->_def['regex']['reportInfo']['isReport'], $page ) )
		{
			$irc->modDebug( 'nzb', 'Report ID: '. $id .' is not a valid report', __FILE__, __LINE__ );
			if ( isset( $irc->_nzbCache[$id] ) )
			{
				$irc->_nzbCache[$id]['searched'] = time();
				$irc->_modules['store']->manualUpdate( '_nzbCache' );
				return $irc->_nzbCache[$id];
			}
			return false;
		}
			
		foreach( $this->_def['regex']['report'] as $regID )
		{
		 	if ( is_array( $regID ) )
		 	{
				if ( is_array( $regID['regex'] ) ) {
					foreach( $regID['regex'] as $regex ) {
						if ( preg_match( $regex, $page, $match ) ) {
							for( $i=1; $i < count($match); $i++ ) {
								$res[$regID['vals'][$i]] = $match[$i];
							}
							break;
						}
					}
				} else {
					if ( preg_match( $regID['regex'], $page, $match ) ) {
						for( $i=1; $i < count($match); $i++ ) {
							$res[$regID['vals'][$i]] = $match[$i];
						}
					}
				}				
			}			
		}
		
		if ( isset( $res['title'] ) )
		{
			if ( ( $m = $this->_getReportSearch( $id, $res['title'] ) ) === false )
			{
				if ( ( $m = $this->_getReportSearch( $id, $this->stringDecode( $res['title'] ) ) ) === false )
				{
					if ( isset( $irc->_nzbCache[$id] ) )
					{
						return $irc->_nzbCache[$id];
					}
					else
					{
						// create report here
						$m = array(
							'report:id' => $id,
							'report:title' => $res['title'] );	
					}
				}
			}
			$this->_checkReports();
			
			if ( isset( $irc->_nzbCache[$id] ) )
				$this->_copyStaticVars( $m, $irc->_nzbCache[$id] );
			
			return $m;
		}
		
		if ( isset( $irc->_nzbCache[$id] ) )
		{
			$irc->_nzbCache[$id]['searched'] = time();
			$irc->_modules['store']->manualUpdate( '_nzbCache' );
			return $irc->_nzbCache[$id];
		}
		
		return false;
	}
	
	/**
	 * Copy static variables from old result to new result
	 *
	 * @param array $newResult - new result
	 * @param array $oldResult - old result
	 * @param array $vals - list of values to copy
	 */
	function _copyStaticVars( &$newResult, $oldResult, $vals = array() )
	{
		if ( count( $vals ) == 0 )
		{
			$vals = array( 'flagMatch', 'score' );	
		}
		
		foreach( $vals as $v )
		{
			if ( ( !isset( $newResult[$v] ) ) &&
			     ( isset( $oldResult[$v] ) ) )
			{
			 	$newResult[$v] = $oldResult[$v];
			 	echo $v.' '.$newResult[$v]."\n";
			}
		}
	}
	
	/**
	 * Get a report based on a title and id
	 *
	 * @param int $id - newzbin id of the report
	 * @param string $title - newzbin title of the report
	 * @return mixed - array if successful, false if failed
	 */
	function _getReportSearch( $id, $title )
	{
		global $irc;
		
		$matches = $this->_searchQuery( sprintf( '^"%s"$', $title ) );
			
		foreach( $matches as $m )
		{				
			if ( $m['report:id'] == $id )
			{
				preg_match( '/^(\w+), (\d+) (\w+) (\d+) (\d+):(\d+):(\d+)/i', $m['report:postdate'], $tMatch );
				$time = strtotime( sprintf( '%d %s %d %d:%d:%d', $tMatch[2], $tMatch[3], $tMatch[4], $tMatch[5], $tMatch[6], $tMatch[7] ) );
				
				$m['report:reported'] = $time;
	
				// filter attributes
				$m['report:attributes']['sorted'] = $this->_arrangeAttributes( $m['report:attributes']['report:attribute'] );
				
				$m['searched'] = time();
				
				$irc->_modules['store']->setVariable( '_nzbCache', $m, $id);
				
				return $m;
			}
		}
		
		return false;
	}
	
	function _checkReports()
	{
	 	global $irc;
	 	
	 	$irc->_modules['store']->manualUpdate( '_nzbCache' );
	 	
	 	if ( ( isset( $irc->_nzbCache ) ) &&
	 	     ( is_array( $irc->_nzbCache ) ) )
	 	{
	        foreach( $irc->_nzbCache as $id => $nzb )
	        {
				if ( $nzb['searched'] < ( time() - ( $this->_config['reportCache'] * 3600 * 24 ) ) )
				{
					unset( $irc->_nzbCache[$id] );
				}
			}
			
			$irc->_modules['store']->manualUpdate( '_nzbCache', true );
	 	}
	}

	/*****************************************************
	 * Worker Thread Stuffs
	 *****************************************************/
	
	function checknzb( &$irc, $vars )
	{
		// check wait variable
		if ( ( $irc->isWorker == true ) || 
		     ( ( $irc->config->useWorker == false ) &&
			   ( $irc->isWorker == false ) ) )
		{
			$irc->_modules['store']->manualUpdate( array( '_nzbWait', '_nzbQueued', '_nzbQError' ) );
			
			if ( ( isset( $irc->_nzbWait ) ) && 
			     ( is_array( $irc->_nzbWait ) ) && 
			     ( count( $irc->_nzbWait ) > 0 ) )
			{
				list( $succ, $errors ) = $this->addIds( $irc->_nzbWait );
				foreach( $succ as $s1 )
				{
					$irc->_nzbQueued[] = $s1;
					foreach( $s1 as $sInfo )
					{
						unset( $irc->_nzbWait[$sInfo['id']] );
					}
				}
				foreach( $errors as $e1 )
				{
					$irc->_nzbQError[] = $e1;
					foreach( $e1 as $eInfo )
					{
						if ( stristr( $eInfo['id'], ',' ) )
						{
							$nIds = explode( ',', $eInfo['id'] );
							
							foreach( $nIds as $anID )
							{
								unset( $irc->_nzbWait[$anID] );
							}
						}
						else
						{
							unset( $irc->_nzbWait[$eInfo['id']] );
						}
					}
				}
				
				// update variables
				$irc->_modules['store']->manualUpdate( array( '_nzbWait', '_nzbQueued', '_nzbQError' ), true );
			}
		}
		
		if ( ( $irc->config->useWorker == true ) &&
		     ( $irc->isWorker == false ) )
		{
			$irc->_modules['store']->manualUpdate( array( '_nzbQueued', '_nzbQError' ) );
			
			if ( ( isset( $irc->_nzbQueued ) ) && 
			     ( is_array( $irc->_nzbQueued ) ) &&
			     ( count( $irc->_nzbQueued ) > 0 ) )
			{		
				foreach( $irc->_nzbQueued as $succ )
				{					
					if ( is_array( $succ ) )
					{
						$vars['addQueued'] = $succ;
						$this->parseTemplate( $msg, 'addSucc', $vars );
					}
					if ( isset( $msg ) )
					{
						$irc->_modules['func']->reply( $irc, $succ[0]['data'], $msg, $succ[0]['data']->notice );
						unset( $msg );
					}
					unset( $vars );
				}
				$irc->_nzbQueued = array();
				$irc->_modules['store']->manualUpdate( '_nzbQueued', true );
			}
			if ( ( isset( $irc->_nzbQError ) ) && 
			     ( is_array( $irc->_nzbQError ) ) && 
			     ( count( $irc->_nzbQError ) > 0 ) )
			{
				foreach( $irc->_nzbQError as $errors )
				{				
					if ( is_array( $errors ) )
					{
						$vars['addQueued'] = $errors;
						$this->parseTemplate( $msg, 'addError', $vars );
					}
					
					if ( isset( $msg ) )
					{
						$irc->_modules['func']->reply( $irc, $errors[0]['data'], $msg, $errors[0]['data']->notice );
						unset( $msg );
					}
					unset( $vars );
				}
				$irc->_nzbQError = array();
				$irc->_modules['store']->manualUpdate( '_nzbQError', true );
			}
		}
	}
	
	/**
	 * Add a bunch of ids to download
	 *
	 * @var array ids - Array of ids/urls to add
	 * @return array - Successful and Failed enties
	 */
	function addIds( $ids )
	{
		global $irc;
		
		$dArray = array();
		$succ = array();
		$errors = array();
		
		foreach( $ids as $tmp => $res )
		{
			if ( !isset( $res['id'] ) )
			{
				$irc->_modules['store']->unsetVariable('_nzbWait', $tmp);
				continue;
			}
			if ( substr( $res['id'], 0, 9 ) == '117114108' )
			{
				if ( ( $title = $this->_addUrl( $res['id'], $res['url'] ) ) !== false )
				{
			 	 	$succ[$this->_findDMatch( $dArray, $res['data'] )][] = array(
					  'id' => $res['id'],
					  'data' => $res['data'],
					  'title' => $title );
			 	}
			 	else
			 	{
					$errors[$this->_findDMatch( $dArray, $res['data'] )][] = array(
					  'id' => $res['id'],
					  'data' => $res['data'],
					  'title' => $this->_error );
				}
			}
		 	else if ( isset( $res['id'] ) )
		 	{
			 	if ( ( $title = $this->_addID( $res['id'], $res['data'], $res['data']->hellaMod ) ) !== false )
			 	{
			 		$val = array(
					  'id' => $res['id'],
					  'data' => $res['data'],
					  'title' => $title);
			 		
			 		if ( isset( $irc->_nzbCache[$res['id']] ) )
			 		{
			 			if ( isset( $irc->_nzbCache[$res['id']]['flagMatch'] ) )
			 			{
			 				$val['flagMatchBridge'] = '{flagMatch}';
							$val['flagMatch'][]['flag'] = $irc->_nzbCache[$res['id']]['flagMatch'];
			 			}
			 		}
			 		
			 	 	$succ[$this->_findDMatch( $dArray, $res['data'] )][] = $val;
			 	}
			 	else
			 	{
			 	 	if ( !preg_match( $this->_def['regex']['download']['DNZBwait'], $this->_error ) )
			 	 	{
						$errors[$this->_findDMatch( $dArray, $res['data'] )][] = array(
						  'id' => $res['id'],
						  'data' => $res['data'],
						  'title' => $this->_error );
					}
					else
					{
						$wait[$this->_findDMatch( $dArray, $res['data'] )][] = $res['id'];
					}
				}
			}
		}
		if ( ( isset( $wait ) ) && ( !$this->_config['download']['hideDnzbWait'] ) )
		{
			foreach( $wait as $dID => $arr )
			{
				$errors[$dID][] = array(
					'id' => implode( ',', $arr ),
					'data' => $dArray[$dID],
					'title' => 'Waiting for Newzbin\'s 5nzbs/minute limit to timeout' );
			}
		}
		elseif ( ( isset( $wait ) ) && ( $this->_config['download']['hideDnzbWait'] ) )
		{
			$irc->_modules['store']->manualUpdate( '_nzbWait' );
			foreach( $wait as $arr )
			{
				foreach( $arr as $nid )
				{
					unset( $irc->_nzbWait[$nid] );
				}
			}
			$irc->_modules['store']->manualUpdate( '_nzbWait', true );
		}
		return array( $succ, $errors );
	}
	
	function _findDMatch( &$dArray, $data )
	{
		$tD = 0;
		if ( ( is_array( $dArray ) ) && ( is_array( $data ) ) )
		{
			var_dump( $dArray );
			foreach( $dArray as $id => $dInfo )
			{
				if ( ( $dInfo['type'] == $data['type'] ) &&
				     ( ( ( ( $dInfo['type'] == SMARTIRC_TYPE_QUERY ) ||
					       ( $dInfo['type'] == SMARTIRC_TYPE_NOTICE ) ) &&
				         ( $dInfo['nick'] == $data['nick'] ) ) ||
					   ( $dInfo['type'] == SMARTIRC_TYPE_CHANNEL ) ) &&
				     ( $dInfo['channel'] == $data['channel'] ) &&
					 ( $dInfo['notice'] == $data['notice'] ) )
				{
					return $id;
				}
				$tD = $id+1;
			}
		}
		$dArray[$tD] = $data;
		return $tD;
	}
	
	/*****************************************************
	 * Newzbin.com login functions
	 *****************************************************/		

	function _getWeb( $url )
	{
		global $irc;

		$req =& new HTTP_Request( );
		$req->setMethod(HTTP_REQUEST_METHOD_GET);
		
		if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
		
		$req->setURL( $url, array( 'timeout' => '30', 'readTimeout' => 30, 'allowRedirects' => true ) );
		
		$request = $req->sendRequest();
		$irc->modDebug( 'nzb', 'request sent for: '.$url, __FILE__, __LINE__ );		
		if (PEAR::isError($request)) {
			$irc->modDebug( 'nzb', 'failed to get '.$url.', error: '.$request->getMessage(), __FILE__, __LINE__ );
			unset( $req, $request );
		} else {
			$body = $req->getResponseBody();
			unset( $req, $request );			
			return $body;
		}
	}

	/**
	 * Get a url from newzbin.com
	 *
	 * @param string $url - URL to get
	 * @return string     - Page retrived
	 * @access private
	 */
	function _getUrl( $url )
	{
		global $irc;
		
		$req =& new HTTP_Request( );
		$req->setMethod(HTTP_REQUEST_METHOD_GET);
		
		if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
		
		$req->setURL( $url, array( 'timeout' => '30', 'readTimeout' => 30, 'allowRedirects' => true ) );
		
		// check login info
		if ( $this->_config['nbLogin'] == true )
		{
			$irc->_modules['store']->manualUpdate('_nzbCookie');
			
			if ( empty( $irc->_nzbCookie ) ) 
			{
			 	$irc->modDebug( 'nzb', 'cookie does not exist', __FILE__, __LINE__ );
				$this->_login();
			}
			
			if ( is_array( $irc->_nzbCookie ) )
			{
				foreach( $irc->_nzbCookie as $cookie )
				{
					$req->addCookie( $cookie['name'], $cookie['value'] );
				}			
			}
		}		
		$request = $req->sendRequest();
		$irc->modDebug( 'nzb', 'request sent for: '.$url, __FILE__, __LINE__ );		
		if (PEAR::isError($request)) {
			$irc->modDebug( 'nzb', 'failed to get '.$url.', error: '.$request->getMessage(), __FILE__, __LINE__ );
			unset( $req, $request );
			return false;
		} else {
			$body = $req->getResponseBody();		
			$cks = $req->getResponseCookies();
			if ( count( $cks ) > 0 )
			{
				$irc->_modules['store']->setVariable( '_nzbCookie', $cks );
			}
			if ( ( $this->_config['nbLogin'] == true ) && ( !$this->_loggedIn( $body ) ) ) {
				if ( $this->_login() ) {
					$irc->modDebug( 'nzb', 'cookie timed out, re-logging in', __FILE__, __LINE__ );
					return $this->_getUrl( $url );
				}
			}
			unset( $req, $request );			
			return $body;
		}
	}
	
	/**
	 * Download a nzb from a random url
	 *
	 * @param string $url  - URL
	 * @param string $file - filename to save
	 */
	function _downloadURL( $url, $file )
	{
		global $irc;	

		$fp = @fopen( $file, 'w' );
		if (!$fp) return 'unable to open file: '.$file;

		$req =& new HTTP_Request( );
		$req->setMethod(HTTP_REQUEST_METHOD_GET);

		if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
		
		$req->setURL( $url, 
			array( 'timeout' => '60', 'readTimeout' => 120, 'allowRedirects' => true ) );

		ini_set( 'memory_limit', ($irc->config->memoryAllocation * 4).'M' );
		$request = $req->sendRequest();
		$irc->modDebug( 'nzb', 'request sent for: '.$url, __FILE__, __LINE__ );		
		if (PEAR::isError($request))
		{
			$irc->modDebug( 'nzb', 'failed to get '.$url.', error: '.$request->getMessage(), __FILE__, __LINE__, SMARTIRC_DEBUG_MODULES );
			fclose( $fp );
			ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
			$msg = $request->getMessage();
			unset( $req, $request );			
			return chr(2).'Error:'.chr(2).' '.$msg;
		}
		else
		{
			$body = $req->getResponseBody();
			unset( $req, $request );			
			fwrite( $fp, $body );
			fclose( $fp );
			
			ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
			return true;
		}	        
	}
    
    function flushDNZB( &$irc )
    {
     	$irc->_nzbDnzbWait = false;
		$irc->unregisterTimeid( $irc->_nzbDnzbWaitID );
		
		$irc->_modules['store']->manualUpdate( array( '_nzbWait', '_nzbDnzbQueue' ) );
		
		$irc->_modules['func']->array_merge( $irc->_nzbWait, $irc->_nzbDnzbQueue );
		
		$irc->_nzbDnzbQueue = array();
		
		$irc->_modules['store']->manualUpdate( array( '_nzbWait', '_nzbDnzbQueue' ), true );

		$this->checknzb( $irc, array() );
	}
    
    function _downloadDNZB( $id, $file, &$data )
    {
		global $irc;

		if ( $irc->_nzbDnzbWait == true )
		{
			$irc->_modules['store']->setVariable( '_nzbDnzbQueue', 
				array(
					'id' => $id,
					'file' => $file,
					'data' => $irc->_modules['func']->getTData( $data ) ),
				$id );
			return 'Try Later, wait 60 seconds for counter to reset';
		}

		$req = &new HTTP_Request();
		$req->setMethod(HTTP_REQUEST_METHOD_POST);
	
    	if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
				
		$req->setURL( $this->_def['url']['download'], array( 'timeout' => 60, 'readTimeout' => 120 ) );
		$req->addPostData( 'username', $this->_config['login']['username'] );
		$req->addPostData( 'password', $this->_config['login']['password'] );
		$req->addPostData( 'reportid', $id );

		$irc->modDebug( 'nzb', 'DNZB request sent for id: '.$id, __FILE__, __LINE__ );				
		ini_set( 'memory_limit', ($irc->config->memoryAllocation * 4).'M' );
		$reqest = $req->sendRequest();
			
		// check for errors
		if ( $req->getResponseCode() != '200' )
		{
			$rCode = $req->getResponseHeader('X-DNZB-RCode');
			switch ( $rCode )
			{
				case 400:
					// bad request (invalid report id)
					{
					 	$irc->modDebug( 'nzb', 'Error: 400, Invalid Report ID: '.$id, __FILE__, __LINE__ );
						ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
						unset( $req, $request );
					 	return 'Invalid Report ID: '.$id;
					}
				case 401:
					// unauthorized, check u/p
					{
						$irc->modDebug( 'nzb', 'Error: 401, Incorrect user details, please check your login details', __FILE__, __LINE__ );
						ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
						unset( $req, $request );						
						return 'Incorrect login details, please check them';
					}
				case 402:
					// premium account required
					{
						$irc->modDebug( 'nzb', 'Error: 402, Premium account Required', __FILE__, __LINE__ );
						ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
						unset( $req, $request );						
						return 'A Premium account is required to download NZB\'s';
					}
				case 404:
					// not found, report doesnt exist
					{
						$irc->modDebug( 'nzb', 'Error: 404, The report does not exist', __FILE__, __LINE__ );
						ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
						unset( $req, $request );
						return 'The report ID: '.$id.', does not exist';
					}
				case 450:
					// try again later
					{
					 	$rMsg = $req->getResponseHeader( 'X-DNZB-RText' );
					 	
					 	preg_match( $this->_def['regex']['download']['DNZBwait'], $rMsg, $time );
						$irc->modDebug( 'nzb', 'Error: 450, '.$rMsg, __FILE__, __LINE__ );
						$irc->_nzbDnzbWait = true;
						$irc->_nzbDnzbWaitID = $irc->registerTimehandler( ($time[1] + 2) * 1000, $this, 'flushDNZB' );
						$irc->_modules['store']->setVariable( '_nzbDnzbQueue', 
							array(
								'id' => $id,
								'file' => $file,
								'data' => $irc->_modules['func']->getTData( $data ) ),
							$id );
						ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
						unset( $req, $request );
						return $rMsg;
					}
				case 500:
					// newzbin is broken
				case 503:
					// newzbin is really broken
					$irc->modDebug( 'nzb', 'Newzbin.com is borked', __FILE__, __LINE__ );
					ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );	
					unset( $req, $request );									
					return 'newzbin.com is broken, please try again later';
			}
		}
		
		if (PEAR::isError($request))
		{
			$irc->modDebug( 'nzb', 'failed to get id: '.$id.', error: '.$request->getMessage(), __FILE__, __LINE__ );
			ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );	
			$msg = $request->getMessage();
			unset( $req, $request );			
			return chr(2).'Error:'.chr(2).' '.$msg;
		}
		else
		{
			$body = $req->getResponseBody();
			unset( $req, $request );

			$fp = @fopen( $file, 'wb' );
			if (!$fp) {
				$irc->modDebug( 'nzb', 'unable to open file: '.$file, __FILE__, __LINE__ );
				ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
				return 'unable to open file: '.$file;
			}		

			fwrite( $fp, $body );
			fclose( $fp );
			
			ini_set( 'memory_limit', $irc->config->memoryAllocation.'M' );
			
			return true;
		}	
		
	}
	
	/**
	 * Login to newzbin.com
	 *
	 * @return bool - True if logged in, else false
	 * @access private
	 */
	function _login() {
	
		global $irc;
		
		$req =& new HTTP_Request( );
		$req->setMethod(HTTP_REQUEST_METHOD_POST);
		
		if ( isset( $irc->config->proxy ) )
		{
			if ( strlen($irc->config->proxy['host']) > 0 )
			{
				if ( strlen($irc->config->proxy['username']) > 0)
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port'],
						$irc->config->proxy['username'],
						$irc->config->proxy['password']);
				}
				else
				{
					$req->setProxy($irc->config->proxy['host'],
						$irc->config->proxy['port']);
				}
			}
		}
				
		$req->setURL( $this->_def['url']['login'], array( 'timeout' => 30, 'readTimeout' => 30 ) );
		$req->addPostData( 'username', $this->_config['login']['username'] );
		$req->addPostData( 'password', $this->_config['login']['password'] );
		$request = $req->sendRequest();
		$irc->modDebug( 'nzb', 'logging into newzbin.com', __FILE__, __LINE__ );		
		if (PEAR::isError($request)) {
			$irc->modDebug( 'nzb', 'failed to get '.$url.', error: '.$request->getMessage(), __FILE__, __LINE__ );
			unset( $req, $request );
		} else {
			if ( $this->_loggedIn( $req->getResponseBody() ) ) {
				$cks = $req->getResponseCookies();
				if ( count( $cks ) > 0 )
				{
					$irc->_modules['store']->setVariable( '_nzbCookie', $cks );
					$irc->modDebug( 'nzb', 'Updated Cookie', __FILE__, __LINE__ );
				}
				$irc->modDebug( 'nzb', 'login successful', __FILE__, __LINE__ );
				unset( $req, $request );
				return true;
			} else {
				$irc->modDebug( 'nzb', 'login Failed', __FILE__, __LINE__ );
				unset( $req, $request );
				return false;
			}
		}
		
	}
	
	/**
	 * Check to see if logged in
	 *
	 * @param string $data - Webpage data
	 * @return bool - true if logged in
	 * @access private
	 */
	function _loggedIn( $data )
	{
		if ( is_array( $this->_def['regex']['loggedIn'] ) )
		{
			foreach( $this->_def['regex']['loggedIn'] as $reg )
			{
				if ( substr($reg, 0, 1) == '!' )
				{
					if ( preg_match( $reg, $data ) )
						return true;
				}
				else
				{
					if ( !preg_match( $reg, $data ) )
						return true;	
				}
			}
			return false;
		}
		else
		{
			if ( preg_match( $this->_def['regex']['loggedIn'], $data ) ) 
				return false;
			else
				return true;
		}
	}
}

?>
Return current item: Nzbirc