<?php                /////////////////////////////////
                     // SABnzbd multiuser interface //
                     /////////////////////////////////

// SABnzbd Configuration

define('S_SAB_APIKEY',	'');
define('S_SAB_HOST', 	'127.0.0.1');
define('S_SAB_PORT',	'8080');
define('S_SAB_USER',	'');
define('S_SAB_PASS',	'');

// Page style

define('S_PAGE_TITLE',	'My Usenet');
define('S_HISTORY_LIMIT', '100');

// Users

define('S_USER_PASS_SALT', 'MyCoolSABWebInterface1337');
global $users;
$users = array(
	'exampleuser' => array(
		'category'	=> 'categoryname',
		'password'	=> '',
		'isGuest'	=> false
	),
	'master' => array(
		'category'	=> '',
		'password'	=> '',
		'isGuest'	=> false
	),
	'guest' => array(
		'category'	=> '',
		'password'	=> '2c5954e56aa288a604392c4e479bd4aa', /* guest */
		'isGuest'	=> true
	)
);

// -------------------------------------------------------------------------- //

session_start();
$html_content = '';

// Controller
// ``````````

if (! isset($_GET['do'])) {
	redirect('?do=login');
} else switch($_GET['do']) {

	case 'login': {
		if (isLoggedIn()) redirect('?do=queue');
		$html_content = html_Login();
	} break;

	case 'queue': {
		requireAuth();		
		$html_content = html_Queue();
	} break;
	
	case 'pause': {
		requireAuth(); requireNonGuest();
		if (! isset($_GET['id'])) perror();
		makeRequest('mode=queue&name=pause&value='.$_GET['id']);
		perror('Download paused.');
	} break;
	
	case 'resume': {
		requireAuth(); requireNonGuest();
		if (! isset($_GET['id'])) perror();
		makeRequest('mode=queue&name=resume&value='.$_GET['id']);
		perror('Download resumed.');
	} break;
	
	case 'delete': {
		requireAuth(); requireNonGuest();
		if (! isset($_GET['id'])) perror();
		makeRequest('mode=queue&name=delete&value='.$_GET['id']);
		perror('Download deleted.');
	} break;
	
	case 'deleteh': {
		requireAuth(); requireNonGuest();
		if (! isset($_GET['id'])) perror();
		makeRequest('mode=history&name=delete&value='.$_GET['id']);
		perror('Removed from history.');
	} break;
	
	case 'add-url': {
		requireAuth(); requireNonGuest();
		if (! isset($_GET['url'])) perror();
		
		$url = $_GET['url'];
		if (filter_var($url, FILTER_VALIDATE_URL) === false) {
			perror('Invalid URL.');
		}
		
		$category = category();
		if (strlen($category)) $category = '&cat='.$category;
		
		makeRequest('mode=addurl'.$category.'&name='.urlencode($url));
		perror('Added NZB file.');
	} break;
	
	case 'add-nzb': {
		requireAuth(); requireNonGuest();
		
		echo 'STILL IN TESTING<br><br><br>';
		
		if (! count($_FILES['nzbfile'])) perror('No files uploaded.');
		
		$error_count = 0;
		for($i = 0, $e = count($_FILES['nzbfile']['name']); $i < $e; $i++) {
		
			$error = $_FILES['nzbfile']['error'][$i];
			if ($error) {
				$error_count++;
				echo "Error ".$error;
				continue;
			}
		
			// SABnzbd api is kinda primitive and only takes one parameter - let's
			//  make sure we get the filename right. Huge hacky workaround here.
			// Could be fixed by picking better CURL options
		
			$tmpname = 'C:\\'.$_FILES['nzbfile']['name'][$i];			
			move_uploaded_file($_FILES['nzbfile']['tmp_name'][$i], $tmpname);
			uploadNZB($tmpname);
			unlink($tmpname);
		}
		perror('Uploaded '.($e - $error_count).' of '.$e.' NZB file(s).');		
	} break;
	
	case 'genhash': {
		if (! isset($_GET['pass'])) die('Usage: ?do=genhash&pass=PASSWORD');
		die( md5( S_USER_PASS_SALT . $_GET['pass'] ) );
	} break;	
	
	case 'try-login': {
		if (! isset($_GET['user']) || ! isset($_GET['pass'])) perror();
		if (isOK($_GET['user'], $_GET['pass'])) {
			$_SESSION['user'] = $_GET['user'];
			$_SESSION['pass'] = $_GET['pass'];
			$_SESSION['info'] = 'Logged in.';
			redirect('?do=queue');
		} else {
			perror('Invalid username or password.');
		}
	} break;
	
	case 'logout': {
		unset($_SESSION['user']);
		unset($_SESSION['pass']);
		perror('Logged out.');
	} break;
	
	default: perror('Invalid request');
	
}

// Helpers
// ```````

function perror($message = 'Invalid request') {
	$_SESSION['info'] = $message;
	redirect( (isset($_SESSION['user'])) ? '?do=queue' : '?do=login');
}

function redirect($url) {
	header('Location: '.$url);
	die();
}

function category() {
	requireAuth();
	global $users;
	return $users[$_SESSION['user']]['category'];
}

function isGuest() {
	requireAuth();
	global $users;
	return $users[$_SESSION['user']]['isGuest'];
}

function isLoggedIn() {
	if (! isset($_SESSION['user'])) return false;
	if (! isOK($_SESSION['user'], $_SESSION['pass'])) return false;
	return true;
}

function requireAuth() {
	if (! isLoggedIn()) perror('Not logged in');
}

function requireNonGuest() {
	if (isGuest()) perror('Insufficient authentication');
}

function isOK($username, $password) {
	global $users;
	if (! isset($users[$username])) return false;
	return (md5(S_USER_PASS_SALT.$password) == $users[$username]['password']);
}

function makeRequest($request, $opts=array()) {
	if (substr($request, 0, 1) == '?') $request = substr($request, 1);
	
	$url =
		'http://'.S_SAB_HOST.':'.S_SAB_PORT.
		'/sabnzbd/api?output=json&apikey='.S_SAB_APIKEY.'&'.$request
	;
	
	$ch = curl_init();
	curl_setopt_array($ch, $opts);
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

	$req = curl_exec($ch);
	curl_close($ch);

	return json_decode($req, true);
}

function uploadNZB($tmpfile) {
	$request = "?mode=addfile";
	$category = category();
	if (strlen($category)) $request .= '&cat='.$category;
	
	makeRequest($request,
		array(CURLOPT_POSTFIELDS => array(
			"name"	=> "@".realpath($tmpfile)
		))
	);
}

function fname($str) {
	return str_replace(
		array('_', '/'),
		array('<wbr>_<wbr>', '<wbr>/<wbr>'),
		htmlspecialchars($str)
	);
}

// HTML Helpers
// ````````````

function html_ActionsFor($id) {
	if (isGuest()) return '';
	return
		'<div class="actions">'.
			'<a title="Remove" class="act_del"    href="?do=delete&id='.$id.'" />'.
			'<a title="Pause"  class="act_pause"  href="?do=pause&id=' .$id.'" />'.
			'<a title="Resume" class="act_resume" href="?do=resume&id='.$id.'" />'.			
		'</div>'
	;
}

function html_ActionsForCompleted($id) {
	if (isGuest()) return '';
	return 
		'<div class="actions">'.
			'<a title="Remove" class="act_del" href="?do=deleteh&id='.$id.'" />'.
		'</div>'
	;
}

function html_Login() {
	return '		
		<form method="get" class="frmLogin">		
			<input type="hidden" name="do" value="try-login" />
			<input type="text" name="user" title="Username" /><br/>
			<input type="password" name="pass" title="Password" /><br/>
			<input type="submit" value="Log in &gt; &gt;" />			
		</form>
	';
}

function html_fStatus($status) {
	switch($status) {
		case 'Completed': 
			return '<span class="stCompleted">Completed</span>';
		
		case 'Failed': 
			return '<span class="stFailed">Failed</span>';
		
		default:
			return $status;
	}
}

function html_Queue() {
	$sab_queue = makeRequest('mode=queue');
	$sab_history = makeRequest('mode=history&start=0&limit='.S_HISTORY_LIMIT);
	$category = category();
	
	// Header
	
	$html = '
		<h1>Status</h1>
		Logged in as <strong>'.$_SESSION['user'].'</strong>
		(<a href="?do=logout">log out</a>).		
		The service is currently <strong>'.$sab_queue['queue']['status'].'</strong>
		at <strong>'.$sab_queue['queue']['kbpersec'].'</strong> KB/sec
		<br/>
		
		<h1>Files</h1>
		
		<table>
			<thead>
				<tr>
					<th>Name</th>
					<th>Status</th>
					<th>Progress</th>
					<th>Size</th>
					<th>ETA</th>
					<th>Actions</th>
				</tr>
			</thead>
			<tbody>
	';	
		
	// Current queue
	
	foreach($sab_queue['queue']['slots'] as $sab_job) {
		if (strlen($category) && $sab_job['cat'] != $category) continue;
		
		$progress = ($sab_job['mb'] > 0)
			? number_format(100 *(1-($sab_job['mbleft']/$sab_job['mb'])), 1)
			: '0.0'
		;
		$display_name = fname($sab_job['filename']);
		if (strlen($sab_job['cat']) && $sab_job['cat'] != '*') {
			$display_name .= ' <em>@'.$sab_job['cat'].'</em>';
		}
		$display_size = str_replace(' ', '&nbsp;', $sab_job['size']);
		
		$html .= '<tr>'.
				'<td>'.$display_name.'</td>'.
				'<td>'.html_fStatus($sab_job['status']).'</td>'.
				'<td>'.$progress.'%</td>'.
				'<td>'.$display_size.'</td>'.
				'<td><span title="ETA: '.$sab_job['eta'].'">...</span></td>'.
				'<td>'.html_ActionsFor($sab_job['nzo_id']).'</td>'.
			'</tr>'."\n"
		;
	}

	// History
	
	foreach($sab_history['history']['slots'] as $sab_job) {
		if (strlen($category) && $sab_job['category'] != $category) continue;
		
		$display_name = fname($sab_job['name']);
		if (strlen($sab_job['category']) && $sab_job['category'] != '*') {
			$display_name .= ' <em>@'.$sab_job['category'].'</em>';
		}
		$display_size = str_replace(' ', '&nbsp;', $sab_job['size']);
		
		
		$html .= '<tr>'.
				'<td>'.$display_name.'</td>'.
				'<td>'.html_fStatus($sab_job['status']).'</td>'.
				'<td>100.0%</td>'.
				'<td>'.$display_size.'</td>'.
				'<td>&nbsp;</td>'.
				'<td>'.html_ActionsForCompleted($sab_job['nzo_id']).'</td>'.
			'</tr>'."\n"
		;
	}

	// Footer
	$disable_if_guest = ( isGuest() ? ' disabled' : '');
	
	$html .= '
			</tbody>
		</table>
	
		<h1>Add to queue</h1>

		<form method="get">
			<input type="hidden" name="do" value="add-url" />
			<input title="URL to NZB file" type="text" name="url" value="" '.$disable_if_guest.'/>
			<input type="Submit" value="Add via URL &gt;&gt;" '.$disable_if_guest.'/>
		</form>
		
		<form method="post" action="?do=add-nzb" enctype="multipart/form-data">
			<input title="Select NZB files to upload" type="file" name="nzbfile[]" multiple '.$disable_if_guest.'/>
			<input type="Submit" value="Upload NZB &gt;&gt;" '.$disable_if_guest.'/>
		</form>
			
	';
	
	return $html;
}

// Page template
// `````````````

?>
<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf8">
		<link rel="stylesheet" type="text/css" href="style.css" />
		<title><?php echo S_PAGE_TITLE; ?></title>
	</head>
	<body>
	
	<div class="header"></div>
	
<?php

if (isset($_SESSION['info'])) {
	echo
		'<div id="info">'.
			$_SESSION['info'].
			'<div class="closer">'.
				'<a href="javascript:;" onclick="document.getElementById(\'info\').style.display = \'none\';">X</a>'.
			'</div>'.
		'</div>'
	;
	unset($_SESSION['info']);
}

echo '<div class="content">'.$html_content.'</div>';

?>	
	</body>
</html>