<?php 
/* 
	WordPress CLI Theme
	R. McFarland 2006

	This is the interpreter for the blog commands. Some commands that do not 
	require DB usage are handled in Javascript (cli.js.php), e.g. cls, login.

	The scheme is very simple, no LALR parsers or anything going on here. Maybe
	someday when I make bash-over-AJAX... Anyhow, if you feel like making new
	commands, just make a PHP file called command-{your-command}.inc.php in the
	'commands' subdirectory (see 'commands/command-hello.inc.php' for an example).
	Remember to update 'help.html' to reflect any new commands (or don't, if
	you're like me). 

	TODO:
	- Handle private posts somehow. There is a provision for passwords in 
		cli.js.php. Probably it would need to be another special case 
		like comments. Would have to md5 or whatever; should check another 
		theme for how the password is passed.
	- "more" (as in hiding part of the post): I don't really care about this. 
	- more (as in less): that would really be cool. I have it half-figured-out
		with the smooth scrolling thing, somebody else lend a hand...
	- Some kind of state (probably in $_SESSION), and changing the prompt from 
		here rather than client-side. This would help making a real
		shell-like experience...
*/ 

session_start();

if(!isset($_SESSION['sessions_work'])){
        //shit... you better watch the sessions directory, it might get out of control
        if(!is_writable('sessions/')){
                die('<p>Sessions are disabled. Navigation will not work. Please make the sessions directory '
                        .'writeable by PHP.</p>');
        }else{
                if(rand(1,100) == 1){
                        //clear old sessions
                        $dh = opendir('sessions');
                        while (($file = readdir($dh)) !== false) {
                                if(filemtime('sessions/'.$file) < (date('U')-3600)){
                                        unlink('sessions/'.$file);
                                }
                        }
                        closedir($dh);
                }

                //hopefully unique hash
                $hash=md5($_SERVER['REMOTE_ADDR']
                        .$_SERVER['HTTP_USER_AGENT']);
                $session_path='sessions/'.$hash.'.session';
                if(!file_exists($session_path)){
                        $fh=@fopen($session_path,'w');
                        $dummy=array();
                        fwrite($fh,serialize($dummy));
                        fclose($fh);
                }
                $fh=@fopen($session_path,'r');
                $_SESSION=unserialize(fread($fh,filesize($session_path)));
                @fclose($fh);
        }
}

$cmd=trim(stripslashes($_REQUEST['c']));
require('../../../wp-blog-header.php');
require_once('cli-config.inc.php');

if(!isset($_SESSION['catq'])){ // there is a difference between WP 1.5 and 2.0 that needs to be handled
	$q="SHOW COLUMNS FROM ".$wpdb->posts;
	$r=mysql_query($q);
	if(!$r){die("cannot get ".$wpdb->prefix." table field names");}
	$hascc=false;
	while($row=mysql_fetch_assoc($r)){
		if($row['Field']=='comment_count'){
			$hascc=true;
			break;
		}
	}
	if($hascc){
		$_SESSION['catq']="SELECT `post_title`, `post_date`, `post_author`, `post_content`, `post_status`, `post_name`, `comment_count` "
			."FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static') AND `ID`=";
	}else{
		$_SESSION['catq']="SELECT `post_title`, `post_date`, `post_author`, `post_content`, `post_status`, `post_name` "
			."FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static') AND `ID`=";
	}
}

if(!isset($_SESSION['current'])){ // set current post if not set already
	$q="SELECT MAX(`ID`) AS c FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static')"; 
	$r=mysql_query($q);
	$_SESSION['current']=mysql_result($r,0,'c');
}




$tokens = preg_split("/[\s]+/ ",$cmd);
$params='';
if(count($tokens)>1){
        $tmp=$tokens[0];
        unset($tokens[0]);
        $params = implode(' ',$tokens);
        $tokens[0]=$tmp;
}


switch(strtolower($tokens[0])){
	case 'help':
	case 'h':
	case '?':
		$f=file_get_contents('help.html');
		echo '<pre>'.str_replace("\n","<br />",$f).'</pre>';
		break;
	case 'gpl':
	case 'license':
		$f=file_get_contents('gpl.html');
		echo '<pre>'.str_replace("\n","<br />",$f).'</pre>';
		break;
	case 'latest':
	case 'last':
	case 'l':
		$q="SELECT MAX(`ID`) AS c FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static')"; 
		$r=mysql_query($q);
		if(mysql_num_rows($r)>0 && mysql_result($r,0,'c')	){
			$_SESSION['current']=mysql_result($r,0,'c');
			cat($_SESSION['current']);
		}
		break;
	case 'next':
	case 'n':
		$q="SELECT MIN(`ID`) AS c FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static')"
			." AND `ID`>".$_SESSION['current'];
		$r=mysql_query($q);
		if(mysql_num_rows($r)>0 && mysql_result($r,0,'c')	){
			$_SESSION['current']=mysql_result($r,0,'c');
			cat($_SESSION['current']);
		}else{
			echo('<p><b>You are at the last post.</b></p>');
		}
		break;
	case 'prev':
	case 'p':
		$q="SELECT MAX(`ID`) AS c FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static')"
			." AND `ID`<".$_SESSION['current'];
		$r=mysql_query($q);
		if(mysql_num_rows($r)>0 && mysql_result($r,0,'c')	){
			$_SESSION['current']=mysql_result($r,0,'c');
			cat($_SESSION['current']);
		}else{
			echo('<p><b>You are at the first post.</b></p>');
		}
		break;
	case 'f':
	case 'first':
		$q="SELECT MIN(`ID`) AS c FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static')"; 
		$r=mysql_query($q);
		if(mysql_num_rows($r)>0 && mysql_result($r,0,'c')	){
			$_SESSION['current']=mysql_result($r,0,'c');
			cat($_SESSION['current']);
		}
		break;
	case 'r':
	case 'rand':
	case 'random':
		$q="SELECT `ID` AS c FROM `".$wpdb->posts."` WHERE (`post_status`='publish' OR `post_status`='static') ORDER BY RAND() LIMIT 1"; 
		$r=mysql_query($q);
		if(mysql_num_rows($r)>0 && mysql_result($r,0,'c')	){
			$_SESSION['current']=mysql_result($r,0,'c');
			cat($_SESSION['current']);
		}
		break;
	case 'current':
	case 'cursor':
		if(isset($tokens[1])){
			$q="SELECT MIN(`ID`) AS c FROM `".$wpdb->posts."` "
				."WHERE (`post_status`='publish' OR `post_status`='static') "
				."AND `ID` >= ".$tokens[1];
			$r=mysql_query($q);
			if($r && mysql_num_rows($r)==1){
				$_SESSION['current']=mysql_result($r,0,'c');
			}
		}
		echo('<p>'.$_SESSION['current'].'</p>');
		break;

	case 'ls':
	case 'dir':
	case 'list':
                $orderby="ID";
                $w='';
                if($params){
                        $w=" AND `post_title` LIKE '%".mysql_real_escape_string($params)."%' ";
                }
                $q="SELECT `ID`,`post_name`, `post_title`, `post_date` FROM `".$wpdb->posts."` "
                        ."WHERE (`post_status`='publish' OR `post_status`='static') $w ORDER BY `$orderby` ASC";
                $r=mysql_query($q);
                echo('<table>');
                for($i=0;$i<mysql_num_rows($r);$i++){
                        list($id,$name,$title,$date)=mysql_fetch_row($r);
                        echo("<tr onclick=\"showpost('$id')\"><td>$id</td><td class=\"linky\">$title</td><td>$date</td></tr>");

                }
                echo('</table>');
                break;
	case 'categories':
		$q="SELECT `cat_ID`,`cat_name`, `category_count` FROM `".$wpdb->categories."` ORDER BY `cat_name` ASC";
		$r=mysql_query($q);
		echo('<table>');
		for($i=0;$i<mysql_num_rows($r);$i++){
			list($id,$name,$count)=mysql_fetch_row($r);
			echo("<tr onclick=\"showcat('$id')\"><td>$id</td><td class=\"linky\">$name</td><td>($count)</td></tr>");
			
		}
		echo('</table>');
		break;
	case 'category':
		if(!isset($tokens[1])){
			echo('<p>No category specified.</p>');
			break;		
		}
		$orderby="ID";
		if(is_numeric($tokens[1])){
			$q="SELECT `ID`,`post_name`, `post_title`, `post_date` FROM `".$wpdb->posts."` as p, `".$wpdb->post2cat."` as pc 
				WHERE (p.`post_status`='publish' OR p.`post_status`='static')
				AND p.`ID`=pc.`post_id`
				AND pc.`category_id`=".$tokens[1]." 
				ORDER BY `$orderby` ASC";
		}else{		
			$q="SELECT `ID`,`post_name`, `post_title`, `post_date` FROM `".$wpdb->posts."` as p, `".$wpdb->post2cat."` as pc, `".$wpdb->categories."` as c 
				WHERE (p.`post_status`='publish' OR p.`post_status`='static')
				AND p.`ID`=pc.`post_id`
				AND pc.`category_id`=c.`cat_ID`
				AND c.`category_nicename`='".$tokens[1]."' 
				ORDER BY `$orderby` ASC";
		}
		$r=mysql_query($q);
		if(!$r || mysql_num_rows($r)==0){
			echo('<p>No category with that id, or specified category is empty.</p>');
		}else{
			echo('<table>');
			for($i=0;$i<mysql_num_rows($r);$i++){
				list($id,$name,$title,$date)=mysql_fetch_row($r);
				echo("<tr onclick=\"showpost('$id')\"><td>$id</td><td class=\"linky\">$title</td><td>$date</td></tr>");
			}
			echo('</table>');
		}
		break;
	case 'read':
	case 'show':
	case 'cat':
		if(isset($tokens[1])){
			cat($tokens[1]);
		}else{
			cat($_SESSION['current']);
		}
		break;
	case 'search':
	case 'find':
                        $q['s'] = addslashes_gpc($params);
                        $search = ' AND (';
                        $q['s'] = preg_replace('/, +/', ' ', $q['s']);
                        $q['s'] = str_replace(',', ' ', $q['s']);
                        $q['s'] = str_replace('"', ' ', $q['s']);
                        $q['s'] = trim($q['s']);
                        if ($q['exact']) {
                                $n = '';
                        } else {
                                $n = '%';
                        }
                        if (!$q['sentence']) {
                                $s_array = explode(' ',$q['s']);
                                $q['search_terms'] = $s_array;
                                $search .= '((post_title LIKE \''.$n.$s_array[0].$n.'\') OR (post_content LIKE \''.$n.$s_array[0].$n.'\'))';
                                for ( $i = 1; $i < count($s_array); $i = $i + 1) {
                                        $search .= ' AND ((post_title LIKE \''.$n.$s_array[$i].$n.'\') OR (post_content LIKE \''.$n.$s_array[$i].$n.'\'))';
                                }
                                $search .= ' OR (post_title LIKE \''.$n.$q['s'].$n.'\') OR (post_content LIKE \''.$n.$q['s'].$n.'\')';
                                $search .= ')';
                        } else {
                                $search = ' AND ((post_title LIKE \''.$n.$q['s'].$n.'\') OR (post_content LIKE \''.$n.$q['s'].$n.'\'))';
                        }
                $q="SELECT `ID`,`post_name`, `post_title`, `post_date` FROM `".$wpdb->posts."` "
                	."WHERE (`post_status`='publish'  OR `post_status`='static') ".$search." ORDER BY `post_date`";
                $r=mysql_query($q);
                if(mysql_num_rows($r)>0){
	                echo('<table>');
                	for($i=0;$i<mysql_num_rows($r);$i++){
                	        list($id,$name,$title,$date)=mysql_fetch_row($r);
                	        echo("<tr onclick=\"showpost('$id')\"><td>$id</td><td class=\"linky\">$title</td><td>$date</td></tr>");
	                }
			echo('</table>');
               	}else{
               		echo('<p>No matching posts.</p>');
		}
		break;
	case 'comments':
		$q="SELECT `comment_author`, `comment_author_url`, `comment_date`, `comment_content`
			FROM `".$wpdb->comments."`
			WHERE `comment_approved`='1' AND `comment_post_ID`=".$_SESSION['current']
			." ORDER BY `comment_date` ASC";
		$r=mysql_query($q);
		if(!$r || mysql_num_rows($r)==0){
			echo('<p>No comments for this post.</p>');
		}else{
			echo('<ol>');
			for($i=0;$i<mysql_num_rows($r);$i++){
				list($author,$url,$date,$content)=mysql_fetch_row($r);
				echo('<li>');
				if($url){
					echo('<a href="'.$url.'" target="_blank">'.$author.'</a>');
				}else{
					echo($author);
				}
				echo(' '.$date.'<br />');
				echo $content;
				echo('</li>');
			}
			echo('</ol>');
		}
		break;
	case 'c':
	case 'comment':
		if(
			isset($_POST['author']) && 
			isset($_POST['email']) && 
			isset($_POST['url']) && 
			isset($_POST['comment'])
		){ 
			$_POST['comment_post_ID']=$_SESSION['current'];
			$_POST['redirect_to']='commredir.html'; //a necessary hack
			@include(ABSPATH.'wp-comments-post.php');
		}else{
			echo ('<p>To enter a comment, enter "c" on a line by itself.</p>');
		}
		break;
	case 'date': //for historical/testing purposes
		echo('<p>'.date('Y-m-d g:i:s a').'</p>');
		break;
	case 'cloud':
		$regen=false;
		if(isset($tokens[1]) && $tokens[1]=='regenerate'){
			$regen=true;
		}
		include('cloud.php');
		break;
        case 'session-handler': //this is a diagnostic. for reliability you might want to take steps
                                //that this returns 'PHP'.
                echo('<p>'.(isset($_SESSION['sessions_work'])?'PHP':'files').'</p>');
                break;
        case 'rss':
        case 'rss2':
                echo('<p><a href="'.get_bloginfo('rss_url').'">Click here for the RSS feed.</a></p>');
                break;
	case '':
		break;
	default:
		if(file_exists('commands/command-'.$tokens[0].'.inc.php')){
                        include('commands/command-'.$tokens[0].'.inc.php');
                        break;
                }
		$w=' 0 ';
                if(is_numeric($tokens[0])){
                        $w="`ID`=".mysql_real_escape_string($tokens[0]);
                }else{
			if(LAST_RESORT && strlen($cmd) > 2){
				echo('<p>Command not found, searching post titles...</p>');
                        	$w="(`post_name` LIKE '%".mysql_real_escape_string($cmd)."%'
                                	OR `post_title` LIKE '%".mysql_real_escape_string($cmd)."%')";
			}else{
                        	$w="`post_name` = '".mysql_real_escape_string($cmd)."'";
			}
                }
                $q="SELECT `ID` as c, `post_name`, `post_title`, `post_date` 
                	FROM `".$wpdb->posts."` 
                	WHERE (`post_status`='publish' 
                		OR 
                		`post_status`='static') 
                		AND ".$w." 
                	ORDER BY `ID` ASC";
                $r=mysql_query($q);
                if($r && mysql_num_rows($r) > 0){
                        if(mysql_num_rows($r) > 1){
                                echo('<p>'.mysql_num_rows($r).' posts found with "'.htmlspecialchars($cmd).'" in title:</p>');
                                echo('<table>');
                                for($i=0;$i<mysql_num_rows($r);$i++){
                                        list($id,$name,$title,$date)=mysql_fetch_row($r);
                                        echo("<tr onclick=\"showpost('$id')\"><td>$id</td><td class=\"linky\">$title</td><td>$date</td></tr>");
                                }
                                echo('</table>');
                        }else{
                                $_SESSION['current']=mysql_result($r,0,'c');
                                cat($_SESSION['current']);
                        }
		}else{
			echo('<p>Unrecognized command. Type \'help\' for assistance.</p>');
		}
}

if(!isset($_SESSION['sessions_work'])){
        $fh=fopen($session_path,'w');
        fwrite($fh,serialize($_SESSION));
        fclose($fh);
}

function cat($id){
		global $wpdb;
		$q=$_SESSION['catq'].$id;
		$r=mysql_query($q);
		if(!$r || mysql_num_rows($r)==0){
			echo('<p>No post with that ID</p>');
		}else{
			$ccount=false;
			list($title,$date,$authorid,$content,$status,$slug,$ccount)=mysql_fetch_row($r);
			$_SESSION['current']=$id;
			$authorinfo=get_userdata($authorid);
			if(
				strpos($content,'<form')!==false ||
				strpos($content,'<input')!==false
			){
				echo('<p>This post is unsuitable for display with the CLI. ');
				if(GUI_URL){
					echo('<a href="'.GUI_URL.'/?'.($status=='static'?'page_id':'p').'='.$id.'">Try the GUI</a>');
				}
				echo('</p>');
				die();
			}
			echo('<h1>'.$title.'</h1>');
			echo('<p>'.$date.' by '.$authorinfo->user_nicename.' (');
			if(!$ccount){
				$q="SELECT COUNT(*) AS c FROM ".$wpdb->comments." 
					WHERE `comment_post_ID`=$id 
					AND `comment_approved`='1'";
				$r=mysql_query($q);
				$ccount=mysql_result($r,0,0);
			}
			switch($ccount){
				case 0: echo('no comments'); break;
				case 1: echo('<span class="linky" onclick="showcomments();">1 comment</span>'); break;
				default: echo('<span class="linky" onclick="showcomments();">'.$ccount.' comments</span>');
			}
			echo(') <a href="'.get_bloginfo('siteurl').'/index.php?'.($status=='static'?'page_id':'p').'='.$id.'">permalink</a>');
			echo('</p>');
			if(is_writable('gimg/') && function_exists('imagegif')){
				preg_match_all('/(<img[^>]*>)/i',$content,$imgs);
				foreach($imgs[1] as $img){
					preg_match('/src\s*=\s*"([^"]*)"/i',$img,$src);
					preg_match('/alt\s*=\s*"([^"]*)"/i',$img,$alt);
					preg_match('/title\s*=\s*"([^"]*)"/i',$img,$tit);
					if(!file_exists('gimg/'.md5($src[1]).'.gif')){
						$type=strtolower(substr($src[1],strpos($src[1],'.')+1));
						if(!strpos($src[1],'://')){
							// is local
							$imagestring=file_get_contents(ABSPATH.$src[1]);
							list($width, $height) = getimagesize(ABSPATH.$src[1]);
						}else{
							$imagestring=file_get_contents($src[1]);
							list($width, $height) = getimagesize($src[1]);
						}
						if(!$imagestring) continue;
						$im=imagecreatefromstring($imagestring);
						//if(!imagefilter($image,IMG_FILTER_GRAYSCALE)) continue; //not in php4
						if (imageistruecolor($im)) {
							imagetruecolortopalette($im, false, 255);
						}
						for ($c = 0; $c < imagecolorstotal($im); $c++) {
							$col = imagecolorsforindex($im, $c);
							$gray = round(0.299 * $col['red'] + 0.587 * $col['green'] + 0.114 * $col['blue']);
							imagecolorset($im, $c, $gray/2, $gray, $gray/2);
						}

						if(CONVERT_PATH && file_exists(CONVERT_PATH)){
							$black=imagecolorallocate($im,0,0,0);
							for($blacken=7;$blacken>=0;$blacken--){
								@imagegif($im,'/tmp/tempgrn'.md5($src[1]).$blacken.'.gif');
								for($r=0;$r<$height;$r+=8){
									imageline ($im, 0, $blacken+$r, 
										$width, $blacken+$r, $black 
										);
								}
							}
							exec(CONVERT_PATH." -delay 100 -loop 1 "
								."/tmp/tempgrn".md5($src[1])."0.gif "
								."/tmp/tempgrn".md5($src[1])."1.gif "
								."/tmp/tempgrn".md5($src[1])."2.gif "
								."/tmp/tempgrn".md5($src[1])."3.gif "
								."/tmp/tempgrn".md5($src[1])."4.gif "
								."/tmp/tempgrn".md5($src[1])."5.gif "
								."/tmp/tempgrn".md5($src[1])."6.gif "
									."/tmp/tempgrn".md5($src[1])."7.gif "
								.'gimg/'.md5($src[1]).'.gif');
							exec("rm /tmp/tempgrn".md5($src[1])."*.gif");
						}else{ // no path to convert 
							@imagegif($im,'gimg/'.md5($src[1]).'.gif');
						}
											
					}
					$content=str_replace($img,
						'<img src="'.get_bloginfo('template_directory').'/gimg/'
						.md5($src[1]).'.gif" alt="'.$alt[1].'" title="'.$tit[1].'" height="'.$height.'" width="'.$width.'" />',
						$content);
				}				
			}
			
			echo('<p>'.nl2br($content).'</p>');
		}
}
?>
