<?php

/**
  * BLOG:CMS: PHP/MySQL Personal Content Management System (CMS)
  * http://blogcms.com/
  * ----------------------------------------------------------------
  *
  * Copyright (C) 2003-2005 Radek HULÁN
  * http://hulan.cz/contact/
  *
  * Based on: 
  * ----------------------------------------------------------------
  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
  * Copyright (C) 2002-2003 The Nucleus Group
  *
  * ----------------------------------------------------------------
  * 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.
**/

class NP_CommentControl extends NucleusPlugin {

var $table_pending,$strNames,$aNames,$iDays;

	function getName() 		{ return 'CommentControl'; }
	function getAuthor()  	{ return 'karma 0.1, 0.2-0.4 Radek HULAN'; }
	function getURL()  		{ return 'http://forum.blogcms.com/'; }
	function getVersion() 	{ return '0.4'; }
	function getDescription() { return 'Tools to handle trolls and comment spam, comment control, prevents comment flooding and posting same comment twice. RSS feed of pending comments now included. It also prevents same comment from same user being posted twice.';}

	function supportsFeature($what) {
		if ($what=='SqlTablePrefix') return 1;
		return 0;
	}

	function install() {
		$this->createOption('quickmenu', 'Show in quick menu', 'yesno', 'yes');
		$this->createOption('names', 'Names of users that cannot place comments (separate with commas)', 'text', '');
		$this->createOption('days', 'Always moderate comments older than x days', 'text', '30');
		$this->createOption('text1', 'Comments to be approved', 'textarea', '<h2>Comments awaiting approval</h2>');
		$this->createOption('text2', 'Comment saved for approval text', 'textarea', '<blockquote id="pending"><p><strong>Your comment was saved. Thank you! I will review it ASAP.</strong></p></blockquote>');
		$this->createOption('text3', 'Comment needs to be approved text', 'textarea', '<blockquote id="pending"><p><strong>Comments must be approved before being published. Thank you!</strong></p></blockquote>');
		$this->createOption('blogpicture','Picture to display:','text','./skins/base/rss20pending.png');
		$this->createOption("delay", "Time in seconds same IP address can post comment again", "text", "30");
		$this->createOption("delaytext", "Delay text", "textarea", 'Sorry, you have to wait at least 30 seconds before posting a new comment!');
		$this->createOption("iptext", "IP posting same comment twice", "textarea", 'Sorry, you cannot post the same comment twice!');
	}
	
	function getTableList() {
		return array(sql_table('plug_cc_pending'));
	}

	function getEventList() {
		return array('PreAddComment', 'QuickMenu');
	}
	
	function init() {
		$this->strNames		= strtolower($this->getOption('names'));
		$this->aNames 		= explode(',', $this->strNames);
		$this->iDays			= intval($this->getOption('days'));
	}
	
	function hasAdminArea() {
		return 1;
	}
	
			
	function event_QuickMenu(&$data) {
		if ($this->getOption('quickmenu') != 'yes') return;
		global $member;
		if (!($member->isLoggedIn() && $member->isAdmin())) return;
		array_push(
			$data['options'], 
			array(
				'title' => 'Comment Control',
				'url' => $this->getAdminURL(),
				'tooltip' => 'See the list of comments that have not yet been verified.',
				'plugin' => 'NP_CommentControl'
			)
		);
	}

	function event_PreAddComment(&$data) {
		global $blog, $manager, $member;

		// check for comment duplicity
		$blogid = getBlogIDFromItemID(intval($data['comment']['itemid']));
		$blog =& $manager->getBlog($blogid);
		$query = sql_query( "select cnumber from " . sql_table( 'comment') . " where cbody='" . sql_escape( commentformatting($data['comment']['body']) ) . "' and cip='" . sql_escape( $data['comment']['ip']) . "' and ctime>=".mysqldate($blog->getCorrectTime()-60*60*24) );
		if ( sql_num_rows($query) > 0)
			doError($this->getOption("iptext"));

		// check for comment flooding for same IP
		$query = sql_query( "select cnumber from " . sql_table( 'comment') . " where cip='" . sql_escape( $data['comment']['ip']) . "' and ctime>=".mysqldate($blog->getCorrectTime()-intval($this->getOption("delay"))) );
		if ( sql_num_rows($query) > 0)
			doError($this->getOption("delaytext"));

		// logged in members can always post 
		if ($member->isLoggedIn())
			$strUserName = $member->getDisplayName();
		else
			$strUserName = $data['comment']['user'];
		
		$itemid = intval($data['comment']['itemid']);
			
		if ($this->needsVerification($itemid, $strUserName))
		{
			// add to list of comments to aprove
			$comment 	= $data['comment'];
			$name		= sql_escape($comment['user']);
			$url		= sql_escape($comment['userid']);
			//  real allowed tags into pseudo tags
			$body = commentformatting($comment['body']);
			// prepare for DB
			$body	= sql_escape($body);
			$host		= sql_escape($comment['host']);
			$ip			= sql_escape($comment['ip']);
			$memberid	= intval($comment['memberid']);
			$timestamp	= date('Y-m-d H:i:s', $comment['timestamp']);
			$itemid		= $comment['itemid'];
			$blogid 	= getBlogIDFromItemID($comment['itemid']);

			$query = 'INSERT INTO '.sql_table('plug_cc_pending').' (CUSER, CMAIL, CMEMBER, CBODY, CITEM, CTIME, CHOST, CIP, CBLOG) '
				   . "VALUES ('$name', '$url', $memberid, '$body', $itemid, '$timestamp', '$host', '$ip', '$blogid')";

			sql_query($query);			
			
			// redirect when adding comments succeeded
			$url = fancyLink($itemid);
			if (!strstr($url, '?')) $url .= '?pending=1'; else $url .= '&pending=1';
			header('Expires: 0');
			header('Pragma: no-cache');
			header('Location: '.$url.'#pending');			
			exit();
		}
	}	
	
	function needsVerification($itemid, $strUserName) {
		global $manager, $member;
		// username in list of evil people
		if ( in_array(strtolower($strUserName), $this->aNames) && strlen($strUserName)>0 ) return true;
		$itemid 	= intval($itemid);
		$blogid 	= getBlogIDFromItemID($itemid);	
		// site members are my friends, but only those who can login!
		if ($member->isLoggedIn() && $member->canLogin()) return false;	
		// item is older than x days
		$timeItem 	= quickQuery('SELECT UNIX_TIMESTAMP(itime) AS result FROM '.sql_table('item').' WHERE inumber=' . intval($itemid));
		$blog 		=& $manager->getBlog($blogid);
		$timeNow	= $blog->getCorrectTime();
		$timeBoundary = $timeNow - ($this->iDays * 24 * 60 * 60);
		if ($timeItem < $timeBoundary) return true;
		return false;
	}

	function doTemplateVar(&$item) {
		global $member;
		if (!($member->isLoggedIn() && $member->isAdmin())) return;
		$id=strval(intval($item->itemid));
		$query = sql_query('SELECT count(*) as total FROM '.sql_table('plug_cc_pending').' WHERE citem='.$id);
		$row=sql_fetch_object($query);
		if ($row->total>0) echo "<span class='r'>pending!</span>";
	}

	function getRSSLink() {   
		global $CONF;
		return $CONF['IndexURL'] . 'action.php?action=plugin&amp;name=CommentControl&amp;type=rss';
	}

	// skinvar plugin can have a blogname as second parameter
	function doSkinVar($skinType, $what = '') {
		global $member, $CONF, $itemid;
		//******** RSS 
		if ($what=='url') 
			if ($member->isAdmin() && $member->isLoggedIn()) 
				echo "<a href='".$this->getRSSLink()."' title='RSS 2.0 of pending comments'><img src='".$this->getOption('blogpicture')."' alt='RSS 2.0 of pending comments' /></a>";
			else
				return;

		if ($skinType != 'item') return;
		
		//******** display warning for non-logged users
		if ($what == 'warning') {
			if (!$member->isLoggedIn() || !$member->isAdmin()) {
				// submit order
				if (intRequestVar('pending') == 1) {
					echo $this->getOption('text2');
					return;
				}
			}
			if ($member->isLoggedIn())
				$strName = $member->getDisplayName();
			else
				$strName = cookieVar('comment_user');		
			// warning
			if ($this->needsVerification($itemid, $strName)) 
				echo $this->getOption('text3');
		}
	}
	
	function putHeader() {   
		global $CONF;
		header ("Content-type: text/xml");
		echo '<'.'?xml version="1.0" encoding="'._CHARSET.'"?'.'>'."\n";
		echo "<rss version=\"2.0\">\n";
		echo "<channel>\n";
		echo "<title>".$CONF['SiteName']."</title>\n";
		echo "<link>".$CONF['IndexURL']."</link>\n";
		echo "<description>".$CONF['AdminEmail']."</description>\n";
		echo "<language>en</language>\n";
		echo "<image>\n";
		echo "<url>".$CONF['AdminURL']."blogcms.gif</url>\n";
		echo "<title>RSS feed of last 20 pending comments.</title>\n";
		echo "<link>".$CONF['IndexURL']."</link>\n";
		echo "</image>\n";
		echo "<docs>http://backend.userland.com/rss</docs>\n";
	} 

	function encode_xml($data){ 
		return strip_tags(entity_to_decimal_value($data)); 
	}

	function putComment($comment) {
		global $CONF;
		if ($comment->member > 0) {
			$result = sql_query("SELECT mname AS nick, murl AS link FROM nucleus_member WHERE mnumber = ".$comment->member);
			$member = sql_fetch_object($result);
			$authorlink = $member->nick;
			$author = "Comment made by: " .$member->nick;
			$title=$comment->title;
		} else {
			$authorlink = $comment->user;
			if (!empty($comment->link)) $authorlink.=" : ".$comment->link;
			$author = "Comment made by: " .$comment->user;
		}
		echo "<item>\n";
		echo "<title>".$this->encode_xml($comment->title)."</title>\n";
		$link = fancyLink($comment->item);
		echo "<link>".$this->encode_xml($link)."#comment".strval($comment->commentid)."</link>\n";
		$urlallow = $CONF['ActionURL'] . '?action=plugin&amp;name=CommentControl&amp;type=allow&amp;id=' . intval($comment->item);
		$urldeny = $CONF['ActionURL'] . '?action=plugin&amp;name=CommentControl&amp;type=deny&amp;id=' . intval($comment->item);
		$data = "Article: ".
				$this->encode_xml($comment->title).
				"\n\nComment ".
				$authorlink." :: \n".$this->encode_xml($comment->body).
				"\n\n".
				"Allow: $urlallow \n".
				"Deny: $urldeny \n";
		echo "<description>".$data."</description>\n";
		echo "<pubDate>".strval(date("r",$comment->ct))."</pubDate>\n";
		echo "</item>\n";
	}

	function putEnd() {
		echo "</channel>\n";
		echo "</rss>\n";
	} 


	function doAction($actionType) {
		global $CONF, $member;
		if (!($member->isLoggedIn() && $member->isAdmin())) 
			die ('Sorry. not allowed');

		if ($actionType == 'rss') {
			$this->putHeader();
			$id = requestVar('id');
			$query = sql_query('select c.id as commentid, UNIX_TIMESTAMP(c.ctime) as ct, c.cbody as body, c.cuser as user, c.cmember as member, i.ititle as title, i.inumber as item from '.sql_table('plug_cc_pending').' c, '.sql_table('item').' i where i.inumber=c.citem');
			while ($row = sql_fetch_object($query))  $this->putComment($row);
			$this->putEnd();
		}

		if ($actionType == 'allow') {
			$id = requestVar('id');
			// get data from pending table
			$query = 'SELECT * FROM ' .sql_table('plug_cc_pending').' WHERE id=' . intval($id);
			$res = sql_query($query);
			$itemid = -1;
			if ($o = sql_fetch_object($res)) {
				$name		= $o->cuser;
				$itemid		= intval($o->citem);
				$blogid		= intval($o->cblog);
				$ip			= $o->cip;
				$host		= $o->chost;
				$timestamp	= $o->ctime;
				$body		= $o->cbody;
				$memberid	= $o->cmember;
				$url		= $o->cmail;
				$name		= $o->cuser;
				// add data to comments table
				$query = 'INSERT INTO '.sql_table('comment').' (CUSER, CMAIL, CMEMBER, CBODY, CITEM, CTIME, CHOST, CIP, CBLOG) '
					   . "VALUES ('$name', '$url', $memberid, '$body', $itemid, '$timestamp', '$host', '$ip', '$blogid')";
				sql_query($query);
			}
			// delete data in pending table
			$query = 'DELETE FROM ' . sql_table('plug_cc_pending') . ' WHERE id=' . intval($id);
			sql_query($query);
			if ($itemid != -1) {
				// clean cache
				if (cleanItem($itemid)) echo "cache cleaned<br />";
				// redirect
				$url = $CONF['PluginURL'].'commentcontrol\\';
				header('Location: '.$url);
				exit();
			} else {
				echo 'not found';
			}
		}
		
		if ($actionType == 'deny') {
			// delete data in pending table
			$id = requestVar('id');
			$itemid = quickQuery('SELECT citem as result FROM ' . sql_table('plug_cc_pending') . ' WHERE id=' . intval($id));
			$query = 'DELETE FROM ' . sql_table('plug_cc_pending') . ' WHERE id=' . intval($id);
			sql_query($query);		
			if ($itemid) {
				// clean cache
				if (cleanItem($itemid)) echo "cache cleaned<br />";
				// redirect
				$url = $CONF['PluginURL'].'commentcontrol\\';
				header('Location: '.$url);
				exit();
			} else {
				echo 'not found';
			}
		}
	}
		

    function doTemplateCommentsVar(&$item, &$comments, $strLinkText) {
        global $member, $manager, $CONF;
        if (!($member->isLoggedIn() && $member->isAdmin())) return;
        $commentId = intval($comments['commentid']);
        if ($member->canAlterComment($commentId)) 
            echo "<a href=\"".$CONF['AdminURL']."?action=commentedit&amp;commentid=".$commentId."\" title=\"Edit\">",$strLinkText,"</a>";
        
    }        

    function _getPendingInfo() {
    	$aResult = array();
    	$query = 'SELECT id, ititle, citem, cbody, cuser, cmail, cmember, UNIX_TIMESTAMP(ctime) as timestamp, chost, cip FROM ' . sql_table('plug_cc_pending') . ', ' . sql_table('item') . ' WHERE inumber=citem';
		  $res = sql_query($query);
		  while ($o = sql_fetch_object($res)) {
			  array_push($aResult, array(
				'itemtitle' 	=> $o->ititle,
				'itemid' 		=> intval($o->citem),
				'comment' 		=> $o->cbody,
				'user'			=> $o->cuser,
				'userid'		=> $o->cmail,
				'memberid'		=> intval($o->cmember),
				'timestamp'		=> intval($o->timestamp),
				'host'			=> strip_tags($o->chost),
				'ip'			=> strip_tags($o->cip),
				'id'			=> intval($o->id)
			  ));
		  }
		  return $aResult;
    }
    
}
?>